Hi,
4dr14n31t0r wrote:I have trouble understanding the ORG preprocessor directive.
OK, let's start with a very simple example (with data and no code at all):
Code: Select all
org 0x0000
dw myThing ;Store the address of the "myThing" label in the output file
myThing:
In this case, the assembler thinks that the output file will be loaded at offset 0x0000 within the segment, so it determines that "myThing" is 2 bytes after that at offset 0x0002, so the file will contain the data 0x0002 (or 0x02, 0x00 as bytes because 80x86 is "little endian").
What if we change the ORG?
Code: Select all
org 0x1234
dw myThing ;Store the address of the "myThing" label in the output file
myThing:
In this case, the assembler thinks that the output file will be loaded at offset 0x1234 within the segment, so it determines that "myThing" is 2 bytes after that at offset 0x1236. The file will contain the data 0x1236 (or 0x36, 0x12 as bytes because 80x86 is "little endian").
Let's add a move instruction:
Code: Select all
org 0x1234
dw myThing ;Store the address of the "myThing" label in the output file
myThing:
mov si,myThing
Here, it's similar to before - the assembler thinks that the output file will be loaded at offset 0x1234 within the segment, so the value 0x1236 is moved into SI.
Let's try some jumps:
Code: Select all
org 0x1234
variable:
dw myThing ;Store the address of the "myThing" label in the output file
myThing:
mov si,myThing
jmp 0x0000:myThing ;Absolute far jump
jmp word [variable] ;Absolute indirect jump
In this case the first jump instruction will become "jmp 0x0000:0x1236". The second jump will become "jmp word [0x1234]", and because the value at offset 0x1234 is 0x1236 it'll end up jumping to offset 0x1236.
Every single thing I've mentioned so far depends on what ORG says; and if you change ORG everything else will change.
Let's try some cases where ORG is irrelevant:
Code: Select all
org 0x0000
variable:
dw 0x1236
myThing:
mov si,0x1236
jmp 0x0000:0x1236 ;Absolute far jump
jmp word [0x1234] ;Absolute indirect jump
jmp myThing
For most of these cases the assembler uses the value you told it to use and doesn't calculate the value itself, so the ORG makes no difference. Of course if you add or remove anything you'll have to calculate all of the values yourself by hand (and if you get one wrong it will create bugs), so it's a massive code maintenance nightmare.
The last instruction ("jmp myThing") is a relative jump. For this the assembler determines the address of the target "myThing" (which depends on ORG and will be wrong if ORG is wrong) and then subtracts the address of the byte after the instruction (which also depends on ORG and will be wrong if ORG is wrong); but this subtraction cancels out. Essentially it's like this:
Code: Select all
(bytes_from_start_of_file_to_target + ORG) - (bytes_from_start_of_file_to_address_after_instruction + ORG)
Which is the same as this:
Code: Select all
bytes_from_start_of_file_to_target - bytes_from_start_of_file_to_address_after_instruction
..which gives the same value regardless of ORG because the ORG cancels out.
However, for "jmp 0x1234" it'd be:
Code: Select all
0x1234 - (bytes_from_start_of_file_to_address_after_instruction + ORG)
..which does depend on ORG because the ORG isn't cancelled out.
Now...
If you tell the assembler that the output file will be loaded at offset 0x1234 within a segment (by using "ORG 0x1234") but the file is actually loaded at offset 0x0000 within a segment, then the assembler will get everything that depended on ORG wrong. For normal code (that uses labels to avoid a code maintenance nightmare) this means that all of your code will be broken when ORG is wrong (except for things like relative jumps which don't depend on ORG).
Cheers,
Brendan