我正在尝试使用GAS(即16位汇编)为x86编写一个小型 Bootstrap 。位于0x7C00的这个命令工作得很好:
.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"
但是,正如您所看到的,“string”的地址被硬编码为$0x7C0F。只要我尝试将硬编码行替换为:
#mov $0x7c0f, %si
mov string, %si
编译失败:
/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
如何让GAS自动解析地址,就像它在32位或64位模式下一样?
编辑
Yikes,我刚刚在Linux源代码arch/x86/realmode/rm/realmode.h中找到了这个注解,他们在那里硬编码了进入保护模式所需的longjump:
这必须是开放编码的,因为气体将阻塞,使用可重新定位的符号为段部分。
这是否意味着GAS无法正确地做到这一点?
1条答案
按热度按时间jobtbby31#
GCC在大多数现代发行版上的默认值是make a PIE executable,错误消息表明您刚刚使用了
gcc -nostdlib foo.s
或其他东西来要求GCC将其汇编并链接到普通的64位PIE可执行文件中!这当然行不通; 16位绝对地址在64位虚拟地址空间中不具有重新定位的空间。通常,您会将
ld
与-Ttext=0x7C00
或其他内容链接,以告诉它计算有用的绝对地址来填充,这些地址将适合16位绝对地址。或者,如果您想使用
gcc
而不是ld
(可能是gcc -m32 -static -no-pie -nostdlib
),则可以使用与生成在Linux下运行的静态可执行文件相同的命令。但是你需要objcopy
或其他东西来获得一个扁平的二进制MBR。(Don不要忘记
.word 0xaa55
Boot 签名。关于使用GNU汇编器和GNU工具链中的其他工具来制作遗留BIOS MBR Boot 扇区,有各种各样的Q& A,大多数标记为bootloader,并提到GAS或用它标记。此外,您希望
mov $string, %si
将该地址用作立即数,而不是从它加载2个字节作为[disp16]
寻址模式。出于同样的原因,您使用了$0x7c0f
而不是0x7c0f
。