Assembly 如何告诉GNU汇编程序在使用未定义的标签时发出警告?
有没有办法告诉GNU汇编程序在编译时警告使用未定义的标签? 让我们假设我输入了一个错误:Assembly 如何告诉GNU汇编程序在使用未定义的标签时发出警告?,assembly,x86,bootloader,gnu-assembler,osdev,Assembly,X86,Bootloader,Gnu Assembler,Osdev,有没有办法告诉GNU汇编程序在编译时警告使用未定义的标签? 让我们假设我输入了一个错误: jmp MyLabell MyLabel: 我不使用链接器。我使用as生成一个对象文件,然后使用objcopy将.o文件转换为原始二进制文件。我这样做是因为我打算在一个只能执行原始二进制文件的环境中运行它(一个实模式引导加载程序)。我想如果我在汇编源代码时使用了未定义的标签,汇编程序会警告我 它可以很好地编译,但是由于从来没有定义过MyLabell,因此它总是会转换为地址0,让程序员不知所措,无动于衷是
jmp MyLabell
MyLabel:
我不使用链接器。我使用as
生成一个对象文件,然后使用objcopy
将.o
文件转换为原始二进制文件。我这样做是因为我打算在一个只能执行原始二进制文件的环境中运行它(一个实模式引导加载程序)。我想如果我在汇编源代码时使用了未定义的标签,汇编程序会警告我
它可以很好地编译,但是由于从来没有定义过MyLabell
,因此它总是会转换为地址0
,让程序员不知所措,无动于衷是否可以告诉as
不要忽略这些问题?如果不是,是否有不可能的原因?就我所记得的(如果我错了,请纠正我),NASM确实关心我只使用定义的标签
我正在使用的GNU汇编程序版本:GNU汇编程序(GNU Binutils)2.29.1
我已经花了整整一个晚上调试代码,只是为了发现重命名标签后,我没有更改对它的所有引用。GNU汇编程序生成一个对象文件。这样的文件不能直接用作二进制文件,必须先链接它,即使没有其他链接。链接过程解析重新定位并修复二进制文件的加载地址,这两项任务是汇编程序自己无法完成的。当链接阶段留下未定义的符号时,链接器会投诉并中止链接过程。您可以使用此行为来检查拼写错误的符号,这是GNU汇编程序自己没有提供的,因为它假定在链接期间,每个未定义的符号都由另一个对象文件提供。这本质上是一个错误 为了回答最初的问题,GNU Assembler
as
假定在当前文件中找不到的任何标签都位于另一个文件中,链接器将在链接时解析该文件。它放置一个伪值作为链接器解析的跳转目标
问题归结为这样一个事实:您从未发现标签是否未定义,因为您没有通过链接器运行它来生成可执行文件。将原始对象文件转换为平面二进制文件可能无法按预期工作。要解决此问题,请执行以下操作:
- 使用GNU汇编程序生成对象文件
- 使用链接器LD设置原点
- 使用OBJCOPY将最终链接的可执行文件转换为二进制文件
如果您正在创建实模式引导加载程序,请不要在GNU汇编程序中使用
.org
指令。它没有达到你期望的效果。这与NASM直接生成原始二进制文件时使用的org
指令不同。您可以使用以下内容:
as --32 boot.s -o boot.o
ld -melf_i386 -nostdlib -Ttext=0x7c00 boot.o -o boot.elf
objcopy -O binary boot.elf boot.bin
使用示例中的LD命令,您可以指定任意数量的.o
文件以链接在一起,或者仅指定一个对象文件(如果需要)
作为上一节的补充,我更喜欢使用带有LD的链接器脚本。对于引导加载程序,我使用链接器将引导签名放置在适当的位置(它可以从程序集文件中删除),并将原点设置为0x7c00。这是一个非常简单的方法,假设引导加载程序只使用
.text
、.data
甚至.rodata
部分:
文件link.ld
:
OUTPUT_FORMAT("elf32-i386");
ENTRY(start);
SECTIONS
{
. = 0x7C00;
.text : {
*(.text);
}
.data : {
*(.data);
*(.rodata);
}
/* Boot signature */
.sig : AT(0x7DFE) {
SHORT(0xaa55);
}
/* Discard common unwanted/unneeded sections */
/DISCARD/ : {
*(.comment);
*(.note.gnu.build-id);
}
}
然后组装并链接文件。在这种情况下,我们指定-Tlink.ld
来使用上面的链接器脚本,并且不再需要使用-Ttext=0x7c00
:
as --32 boot.s -o boot.o
ld -melf_i386 -nostdlib -Tlink.ld boot.o -o boot.elf
objcopy -O binary boot.elf boot.bin
如果未找到类似
MyLabel1
的标签,则正确使用链接器生成可执行文件应产生类似于此的错误:
boot.o:(.text+0x1):对“MyLabell”的未定义引用
原点和实模式代码 GNU链接器不了解。将在物理地址0x07c00处加载引导加载程序,但有多种方法可以寻址该位置。在实模式段中:偏移寻址段和偏移组合定义物理地址。计算为段*16+偏移量。在链接器脚本或
.Ttext=
选项中选择的原点必须与加载到段寄存器(尤其是DS)中的段组合为0x07c00。如果将段设置为0x0000,则需要的偏移量为0x7c00,因为0x0000*16+0x7c00=0x07c00。使用0x7c0段,需要0x0000的偏移量为0x7c0*16+0x0000=0x07c00
我的链接器脚本link.ld
假设您加载了带有0x0000的DS段寄存器。用于段的值为0x7c0,因此需要将链接.ld
更改为使用=0x0000代码>而不是=0x7C00代码>
如果使用=0x0000
作为原点,然后还需要通过从中减去0x7c00来调整引导加载程序位置。行.sig:AT(0x7DFE){
必须更改为.sig:AT(0x1FE){
。如果在运行LD时不使用链接器脚本并指定原点,则在链接时必须将其更改为-Ttext=0x0000
。GNU汇编程序将假定当前文件中未看到的任何标签都存在于另一个文件中。这将留给链接进程(ld
或gcc
可用于链接)来确定在将所有对象拉到一起时是否存在未定义的引用。那么您就做错了。听起来您正在进行某种操作系统开发。您可以组装文件(或编译)对于多个对象文件,使用链接器生成独立的可执行文件,然后使用objcopy
将完全链接的可执行文件转换为二进制格式,以便在裸机环境中轻松使用。事实上,您正在转换原始ob