I am learning assembly for fun and its just my 3rd day today. Perhaps I mis-understood the location counter in linker script. As per my understanding, location counter defines at which address in memory, the sections must be loaded in memory (physical or virtual).
However, the following linker script taken from this SO post seems to alter the resulting image (to put the magic number in last 2 bytes of resulting MBR image).
link.ld
SECTIONS
{
/* The BIOS loads the code from the disk to this location.
* We must tell that to the linker so that it can properly
* calculate the addresses of symbols we might jump to.
*/
. = 0x7c00;
.text :
{
__start = .;
*(.text)
/* Place the magic boot bytes at the end of the first 512 sector. */
. = 0x1FE;
SHORT(0xAA55)
}
}
My code is:
main.S
.code16
mov $msg, %si
mov $0x0e, %ah
loop:
lodsb
or %al, %al
jz halt
int $0x10
jmp loop
halt:
hlt
msg:
.asciz "hello world"
I assemble and link with:
as -g -o main.o main.S
ld --oformat binary -o main.img -T link.ld main.o
qemu-system-x86_64 -hda main.img
Sooner I realized that the option --oformat binary
has to do something with this, as excluding this does not create 512 byte image. Maybe I should be looking for ELF vs binary format? Can someone please help me understand why binary
format was used, how it interprets location counter (as it should have done something with . = 0x7C00
as well)?
Hexdump of resulting 512 byte hello world image gives me this :
00000000 bf 0f 7c b4 0e ac 08 c0 74 04 cd 10 eb f7 f4 68 |..|.....t......h| 00000010 65 6c 6c 6f 20 77 6f 72 6c 64 00 66 2e 0f 1f 84 |ello world.f....| 00000020 00 00 00 00 00 66 2e 0f 1f 84 00 00 00 00 00 66 |.....f.........f| 00000030 2e 0f 1f 84 00 00 00 00 00 66 2e 0f 1f 84 00 00 |.........f......| 00000040 00 00 00 66 2e 0f 1f 84 00 00 00 00 00 66 2e 0f |...f.........f..| 00000050 1f 84 00 00 00 00 00 66 2e 0f 1f 84 00 00 00 00 |.......f........| 00000060 00 66 2e 0f 1f 84 00 00 00 00 00 66 2e 0f 1f 84 |.f.........f....| 00000070 00 00 00 00 00 66 2e 0f 1f 84 00 00 00 00 00 66 |.....f.........f| 00000080 2e 0f 1f 84 00 00 00 00 00 66 2e 0f 1f 84 00 00 |.........f......| 00000090 00 00 00 66 2e 0f 1f 84 00 00 00 00 00 66 2e 0f |...f.........f..| 000000a0 1f 84 00 00 00 00 00 66 2e 0f 1f 84 00 00 00 00 |.......f........| 000000b0 00 66 2e 0f 1f 84 00 00 00 00 00 66 2e 0f 1f 84 |.f.........f....| 000000c0 00 00 00 00 00 66 2e 0f 1f 84 00 00 00 00 00 66 |.....f.........f| 000000d0 2e 0f 1f 84 00 00 00 00 00 66 2e 0f 1f 84 00 00 |.........f......| 000000e0 00 00 00 66 2e 0f 1f 84 00 00 00 00 00 66 2e 0f |...f.........f..| 000000f0 1f 84 00 00 00 00 00 66 2e 0f 1f 84 00 00 00 00 |.......f........| 00000100 00 66 2e 0f 1f 84 00 00 00 00 00 66 2e 0f 1f 84 |.f.........f....| 00000110 00 00 00 00 00 66 2e 0f 1f 84 00 00 00 00 00 66 |.....f.........f| 00000120 2e 0f 1f 84 00 00 00 00 00 66 2e 0f 1f 84 00 00 |.........f......| 00000130 00 00 00 66 2e 0f 1f 84 00 00 00 00 00 66 2e 0f |...f.........f..| 00000140 1f 84 00 00 00 00 00 66 2e 0f 1f 84 00 00 00 00 |.......f........| 00000150 00 66 2e 0f 1f 84 00 00 00 00 00 66 2e 0f 1f 84 |.f.........f....| 00000160 00 00 00 00 00 66 2e 0f 1f 84 00 00 00 00 00 66 |.....f.........f| 00000170 2e 0f 1f 84 00 00 00 00 00 66 2e 0f 1f 84 00 00 |.........f......| 00000180 00 00 00 66 2e 0f 1f 84 00 00 00 00 00 66 2e 0f |...f.........f..| 00000190 1f 84 00 00 00 00 00 66 2e 0f 1f 84 00 00 00 00 |.......f........| 000001a0 00 66 2e 0f 1f 84 00 00 00 00 00 66 2e 0f 1f 84 |.f.........f....| 000001b0 00 00 00 00 00 66 2e 0f 1f 84 00 00 00 00 00 66 |.....f.........f| 000001c0 2e 0f 1f 84 00 00 00 00 00 66 2e 0f 1f 84 00 00 |.........f......| 000001d0 00 00 00 66 2e 0f 1f 84 00 00 00 00 00 66 2e 0f |...f.........f..| 000001e0 1f 84 00 00 00 00 00 66 2e 0f 1f 84 00 00 00 00 |.......f........| 000001f0 00 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 00 55 aa |.f............U.| 00000200
I don't understand the impact of . = 0x7C00
here? Is that info lost? (maybe not needed because the GRUB would anyway load it at 0x7C00)