我正在学习汇编的乐趣,而这只是我今天的第三天。也许我误解了链接描述文件中的位置计数器。根据我的理解,位置计数器定义了内存中的哪个地址,这些段必须加载到内存中(物理或虚拟)。
但是,从该SO帖子中获取的以下链接程序脚本似乎会更改生成的图像(将幻数放在生成的MBR图像的最后2个字节中)。
链接
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)
}
}
我的代码是:
电源
.code16
mov $msg, %si
mov $0x0e, %ah
loop:
lodsb
or %al, %al
jz halt
int $0x10
jmp loop
halt:
hlt
msg:
.asciz "hello world"
我组装并链接:
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
很快我意识到该选项--oformat binary
必须对此做一些事情,因为排除该选项不会创建512字节的图像。也许我应该在寻找ELF vs二进制格式?有人可以帮我理解为什么使用binary
格式,如何解释位置计数器(因为它也应该做些什么. = 0x7C00
)吗?
生成的512字节的hello世界映像的十六进制转储给我这个:
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
我不明白. = 0x7C00
这里的影响吗?该信息丢失了吗?(可能不需要,因为GRUB始终会在0x7C00加载它)
. = 0x7c00;
.text :
{
__start = .;
*(.text)
/* Place the magic boot bytes at the end of the first 512 sector. */
. = 0x1FE;
SHORT(0xAA55)
}
0x7C00,您正在告诉链接程序(这不是BTW的汇编语言,不相关)。我希望接下来的事情是在地址空间(对于处理器)中的地址0x7C00处。下方带有.text,这表示我们希望从地址0x7C00开始链接.text代码。因此,如果有任何特定位置,则它将基于该地址。
__start给我到目前为止的地址(.text中)
*(。text)将所有.text代码放在此处
。= 0x1FE将指针移动到.text中的0x1FE
SHORT(0xAA55)将这两个字节放在.text中的偏移量0x1Fe和0x1FF处
因此,假设代码适合,那么将产生一个0x200字节的Blob,该地址将在地址空间的0x7C00处加载。
现在,当您objcopy -O二进制hello.elf hello.bin
该工具将查找第一个可加载对象,而输出文件的第一部分就是该第一个可加载对象。如果这是“二进制”中仅有的内容,则0x200字节将进入文件hello.bin。
该-O二进制文件格式丢失了告诉处理器0x7C00所需信息的信息。精灵拥有它,其他拥有它,但是那个没有。
此外,如果在0x7C00具有0x200字节,在0x8000具有2个字节,那么-O二进制输出将为0x402字节长。前0x200字节来自最低可加载内容的0x7C00的.text,然后是0x200字节的填充字节,因此,相对于文件开头的第二个字节位于正确的位置(如果要使用hello.bin并放入在0x7c00,则这两个字节将在0x8000。
如果您在0x7C00处有这些0x200,并且要在链接脚本中添加另一个项目,并在0x7000处使用0x02字节,那么hello.bin将以这两个字节开头,将有0xBFE填充字节,然后是.text的0x200字节。因此,当将bin文件以0x7000加载到内存中时,两个字节和0x200字节位于正确的位置。
因此,objcopy -O binary本质上创建了一个需要加载的内存映像,有时使用填充,但是没有有关该加载的起始地址的信息。您必须知道。
elf文件也将以某种形式包含0xAA55,我认为整个0x200字节是.text中显示的一件事,但也许将其分为两部分。取决于创建小精灵的工具的填充方式和填充方式。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句