NASM / LD"搬迁截断以适应:R_386_16" [英] nasm/ld "relocation truncated to fit: R_386_16"

查看:469
本文介绍了NASM / LD"搬迁截断以适应:R_386_16"的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

大会:

[BITS 16]

global _start

_start:
    mov ax, 0x07C0
    mov ds, ax

    mov si, hw
    call print_string
    jmp $

print_string:
    mov ah, 0x0E
.char:
    lodsb
    cmp al, 0
    je .exit
    int 0x10
    jmp .char
.exit: ret

times 0x100-($-$$) db 0

hw: db "Hello, World!", 0

times 510-($-$$) db 0
dw 0xAA55

与装配这样的:

$ nasm file.asm -felf -o file.o

然后用它链接:

$ ld -melf_i386 -o file.bin file.o --oformat binary

提供了以下错误:

Gives the following error:

file.asm:(.text+0x6): relocation truncated to fit: R_386_16 against `.text'

与codeA位摆弄之后,我想通了,改变 MOV SI,汉王 MOV SI,为0x100 工作正常。但什么是标签的意义呢?

After fiddling with the code a bit, i figured out that changing mov si, hw to mov si, 0x100 works fine. But then what's the point of labels?

我的猜测是,LD不能产生16位二进制文​​件,所以它取代硬件有32位地址,而不是16位地址。然后,它抱怨,因为我的程序试图把32位值到一个16位的寄存器。

My guess is that ld can't generate 16 bits binary files, so it replaces hw with a 32 bit address instead of a 16 bit address. And then it complains because my program tries to put a 32 bit value into a 16 bit register.

有一些说法,我可以传递给NASM / LD,使这项工作?

Is there some argument i can pass to nasm/ld to make this work?

编辑:

小精灵不支持16位,唯一的输出格式NASM支持实际上至极指出它支持16位 NASM -hf 的OBJ,但我不能找到它连接。

elf doesn't support 16 bit, the only output format nasm supports wich actually states it supports 16 bit in nasm -hf is .obj, but i can't find a linker for it.

NASM手册:

在ELF32规范并未对8位和16位值提供搬迁,但GNU LD链接器将这些作为一个扩展。 NASM可以生成GNU兼容的搬迁,让16位code为ELF使用GNU ld的链接。如果NASM与-w + GNU精灵的扩展选项时,将发出警告时产生这些重定位之一。

The ELF32 specification doesn't provide relocations for 8- and 16-bit values, but the GNU ld linker adds these as an extension. NASM can generate GNU-compatible relocations, to allow 16-bit code to be linked as ELF using GNU ld. If NASM is used with the -w+gnu-elf-extensions option, a warning is issued when one of these relocations is generated.

添加 -w + GNU精灵的扩展确实显示警告信息,但LD仍然给出了同样的错误。

Adding -w+gnu-elf-extensions does indeed show a warning, but ld still gives the same error.

推荐答案

首先我建议你可以考虑使用的 i686的ELF交叉编译避免一些gotchyas,以后可以咬你,你发展你的内核。

First of all I recommend you consider using an i686 ELF Cross compiler to avoid some gotchyas that can later bite you as you develop your kernel.

没有prevents你其产生不需要的修正完全解决平板二进制文件斌选项。它可以作为没有任何连接工序的引导扇区。的一面是,所有的code的是在相同的。外部汇编语句可以包含在%包含指令,类似的 C 的的包含指令。

Nothing prevents you from using ELF as the object file type with NASM, but it is often simpler to use the -f bin option that generates a fully resolved flat binary file that needs no fixups. It can be used as a boot sector without any linking step. The down side is that all the code has to be in the same. External assembler statement can be included with the %include directive, similar to C's include directive.

对于这个工作,你必须原点放在汇编文件中,这样的 NASM 的知道什么基本偏移(原点)用来产生绝对地址(标签等)。你会修改你的汇编code和顶部补充一点:

For this to work you have to place the origin point in the assembler file so that NASM knows what the base offset (origin point) is needed for generating absolute addresses (for labels etc). You would modify your assembly code and add this at the top:

[ORG 0x0000]

这仅在使用 -f斌输出选项时适用,该指令将抛出一个错误的其它输出类型,如 。在这种情况下,我们使用为0x0000,因为你的code假定该段0x07c0其移入的 DS 的。 0x07c0:为0x0000映射到物理地址(0x07c0<&4;)+ 0×0000 = 0x07c00这是我们的bootloader将被加载到内存

This only applies when using -f bin output option, this directive will throw an error for other output types like -f elf. In this case we use 0x0000 because the segment your code assumes is 0x07c0 which is moved into DS. 0x07c0:0x0000 maps to physical address (0x07c0<<4)+0x0000 = 0x07c00 which is where our bootloader will be loaded into memory.

如果您不指定 [组织为0x0000] ,然后组织= 0×0000是默认情况下使用时, -f斌输出选项,因此它实际上不是需要指定它。它只是使得它更加清晰,以读者通过显式地使用它。

If you don't specify [org 0x0000], then org = 0x0000 is the default when using the -f bin output option, so it isn't actually necessary to specify it. It just makes it much clearer to a reader by using it explicitly.

为了组装成一个二进制文件,你可以这样做:

In order assemble this into a binary file you could do:

nasm file.asm -fbin -o file.bin

这将输出名为 file.bin file.asm 组装。没有链接步骤是一个平面的二进制文件必要的。

This would output a flat binary file called file.bin assembled from file.asm.No linking step is needed.

在您的例子中,你正在使用的 ELF 的。有可能是做这样一对夫妇的原因。您生成的二进制文件可能是多个对象的组合(的.o )的文件,或者你可能希望生成调试符号与喜欢的 GDB <调试器中使用/ em>的。无论你的原因,这可以使用以下命令来完成:

In your example you are using ELF. There may be a couple reasons for doing it this way. Your generated binary file may be the combination of multiple object (.o) files, or you may wish to generate debug symbols to be used with a debugger like GDB. Whatever your reason this can be done using these commands:

nasm file.asm -felf -o file.o
ld -melf_i386 -Ttext 0x0 -o file.bin file.o --oformat binary

-Ttext为0x0 将是原点符合您的code。为0x0000在这种情况下你会使用 ORG 指令已使用你的 NASM 的使用 -f使用相同的值斌输出选项。如果你写你的code承担与code像偏移的0x7c00:

-Ttext 0x0 would be the origin point that matches your code. 0x0000 in this case is the same value you would have used with the ORG directive had you used NASM with the -f bin output option. If you had written your code to assume an offset of 0x7c00 with code like:

xor ax, ax     ; AX = 0
mov ds, ax     ; DS = 0

随后的文本的段必须与指定:

ld -melf_i386 -Ttext 0x7c00 -o file.bin file.o --oformat binary


您的问题可能是:为什么我们需要明确设置一个值的的文本的段的基?其原因是,为的 LD 的的默认值是依赖于你的目标(通常是你正在运行的平台)操作系统。如果你是在Linux上,默认情况下的 LD 的将尝试创建用于Linux输出。在Linux上,默认的开始的文本的段通常是指定时 0x08048000 -m elf_i386 。当然,这是一个32位的值。


Your question may be: why do we need to explicitly set a value for the base of the TEXT segment? The reason is that the the default for LD is dependent on the the OS you are targeting (usually for the platform you are currently running on). If you are on Linux, by default LD will attempt to create output for Linux. On Linux the default for the start of the TEXT segment is usually 0x08048000 when specifying -m elf_i386. This is of course a 32-bit value.

任何地方,需要一个绝对地址,将尝试添加 0x08048000 (或潜在的一些大型地址)给它。所以像这样的指令:

Any place an absolute address was needed it would attempt to add 0x08048000 (or potentially some other large address) to it. So an instruction like this:

mov si, hw

将尝试硬件的地址转移到16位寄存器的 SI 的。链接器会尝试解决这0x08048000 +偏移创造了平板二进制输出文件时,硬件。因为你必须在只需要一个16位的值的指令正在使用32位的值,你会得到一个警告/错误。的 LD 的将32位值截断为16位,不幸的是可能会产生不正确的16位地址。

Would attempt to move the address of hw into the 16-bit register SI. The linker would have attempted to resolve this to 0x08048000 + offset of hw when creating the flat binary output file. Because you have a 32-bit value being used in an instruction that only takes a 16-bit value, you will get a warning/error. LD will truncate the 32-bit value to 16-bit, unfortunately that would likely produce an incorrect 16-bit address.

这篇关于NASM / LD&QUOT;搬迁截断以适应:R_386_16&QUOT;的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆