I'm trying to write a small bootloader for x86 using GAS, i.e., 16-bit assembly. This, located at 0x7C00, works perfectly:
.code16
.text
.globl main
main:
mov $0xb800, %ax
mov %ax, %es
mov $0x7c0f, %si
movb (%si), %al
mov %al, %es:0
hlt
string:
.byte 'A'
.section .note.GNU-stack,"",@progbits
.section .note.gnu.property,"x"
However, as you can see, the address of "string" is hardcoded to be $0x7C0F. As soon as I try to replace that hardcoded line by:
#mov $0x7c0f, %si
mov string, %si
compilation fails:
/usr/bin/ld: /tmp/cctVBx2h.o: relocation R_X86_64_16 against `.text' can not be used when making a PIE object; recompile with -fPIE /usr/bin/ld: failed to set dynamic section sizes: bad value
How can I make GAS resolve the addresses automatically, as it would also do in 32-bit or 64-bit mode?
Edit
Yikes, I just found this comment in the Linux source code, arch/x86/realmode/rm/realmode.h where they hardcode the longjump required to enter protected mode:
This must be open-coded since gas will choke on using a relocatable symbol for the segment portion.
Does this mean GAS just is unable to do this properly?