使用带有 16 位 x86 的 GNU LD 的相对地址不正确 [英] Incorrect relative address using GNU LD w/ 16-bit x86

查看:33
本文介绍了使用带有 16 位 x86 的 GNU LD 的相对地址不正确的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,我的本机系统是 amd64,Windows,使用 cygwin,以及 GNU 工具链和 binutils.

Firstly, my native system is amd64, Windows, using cygwin, and the GNU toolchain and binutils.

我正在编写一个 x86 引导加载程序,但无法让 ld 生成正确的相对地址.我已经准备了这个最小的可重复示例:

I am writing an x86 bootloader but can't get ld to generate correct relative addresses. I've prepared this minimum reproducible example:

main.s

.code16
.global _start
.section .text
_start:
    call other
    hlt

other.s

.code16
.global other
.section .text
other:
    mov $0xFFFF, %ax
    ret

script.ld

ENTRY(_start);

SECTIONS {
    .text : {
        *(.text);
    }
}

要重现,请执行:

$ as main.s -o a.o
$ as other.s -o b.o
$ ld -T script.ld *.o -o c.o

然后当您检查 c.o 时使用:

Then when you examine c.o using:

$ objdump -sD -m i8086 c.o

c.o:     file format pei-x86-64

Contents of section .text:
 200000000 e80b00f4 90909090 90909090 90909090  ................
 200000010 b8ffffc3 90909090 90909090 90909090  ................

Disassembly of section .text:

00000000 <_start>:
   0:   e8 0b 00                call   e <__major_subsystem_version__+0x9>
   3:   f4                      hlt
   4:   90                      nop
   5:   90                      nop
   6:   90                      nop
   7:   90                      nop
   8:   90                      nop
   9:   90                      nop
   a:   90                      nop
   b:   90                      nop
   c:   90                      nop
   d:   90                      nop
   e:   90                      nop
   f:   90                      nop

00000010 <other>:
  10:   b8 ff ff                mov    $0xffff,%ax
  13:   c3                      ret
  14:   90                      nop
  15:   90                      nop
  16:   90                      nop
  17:   90                      nop
  18:   90                      nop
  19:   90                      nop
  1a:   90                      nop
  1b:   90                      nop
  1c:   90                      nop
  1d:   90                      nop
  1e:   90                      nop
  1f:   90                      nop

注意地址 0 处的 call 指令的相对地址如何指向 0xE 而不是 0x10,其中应该.

Notice how the relative address for the call instruction at address 0 points to 0xE instead of 0x10 where it should.

虽然目标文件是 pe[i]-x86-64 格式,但指令仍然是 16 位的(因此 -m i8086 选项可以正确反汇编).

While the object files are in pe[i]-x86-64 format the instructions are still 16-bit (hence the -m i8086 option for proper disassembly).

我认为地址错误的原因是因为 ld 认为代码是 64 位信任文件格式并解析错误地址.然而,这个理论如履薄冰,因为 a.o 中的重定位信息说:

The reason why I think the address is wrong is because ld believes the code is 64-bit trusting the file format and resolves wrong addresses. This theory is on thin ice however because the relocation information in a.o says:

$ objdump -sDr -m i8086 a.o

a.o:     file format pe-x86-64

Contents of section .text:
 0000 e80000f4 90909090 90909090 90909090  ................

Disassembly of section .text:

00000000 <_start>:
   0:   e8 00 00                call   3 <_start+0x3>
                        1: R_X86_64_PC16        other
   3:   f4                      hlt
[...]

其中重定位类型为 R_X86_64_PC16 据我所知,它将地址截断为 16 位,并且应该可以工作.

where the relocation type is R_X86_64_PC16 which truncates the address down to 16-bits as far as I can tell, and should work.

在我的实际项目中,我使用 ld 像上面一样组合目标文件,然后使用 objcopy 将其转换为平面二进制映像,以便作为软盘启动使用模拟器.我这样做是因为 ld 根本无法将目标文件转换为平面二进制文件.

In my actual project I use ld to combine object files just like above then use objcopy to convert it into a flat binary image in order to boot as a floppy disk using an emulator. I do it this way because ld simply cannot convert object files into flat binaries.

我尝试在链接之前更改 aobo 的对象格式,但我的系统不支持 32 和 64 位对象格式以外的任何其他格式,即我可以't(或认为我不能)使用 objcopy 来做到这一点.

I've tried to change the object formats of a.o and b.o before linking but my system does not support anything other than 32 and 64 bit object formats i.e. I can't (or don't think I can) use objcopy to do it.

推荐答案

正如@NateEldredge 和@MichaelPetch 指出的那样,这不是任何工具或代码的问题,而是我的工具链的问题.此后,我为与操作系统无关的通用 x86-32 (i686) 目标平台编译了 GCC 交叉编译器和 binutils.

As @NateEldredge and @MichaelPetch have pointed out this is not a problem with any of the tools or the code but with my toolchain. I have since compiled a GCC cross-compiler and binutils for an OS-agnostic generic x86-32 (i686) target platform.

对于在网上搜索时找到此答案的其他人:https://wiki.osdev.org/GCC_Cross-Compiler

For others who find this answer while searching the net: https://wiki.osdev.org/GCC_Cross-Compiler

这篇关于使用带有 16 位 x86 的 GNU LD 的相对地址不正确的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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