使用 GNU LD w 16-bit x86 的相对地址不正确。

问题描述 投票:0回答:1

首先,我的原生系统是amd64,Windows,使用cygwin,以及GNU工具链和binutils。

我正在写一个x86的bootloader,但是不能得到 ld 来生成正确的相对地址。我准备了这个最低限度的可重现的例子。

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 的使用。

$ 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

请注意,相对地址为 call 地址指令 0 指向 0xE 而不是 0x10 的地方。

当对象文件在 pe[i]-x86-64 格式的指令仍然是16位的(因此,在这里的 -m i8086 选项,以便正确拆卸)。)

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

$ 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位。 据我所知,应该可以用。

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

我曾试着改变了 a.ob.o 但我的系统除了32位和64位的对象格式外,不支持任何其他格式,也就是说,我不能(或认为不能)使用 objcopy 来做。

assembly x86 ld gas object-files
1个回答
2
投票

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

对于其他在网上搜索时发现这个答案的人。https:/wiki.osdev.orgGCC_Cross-Compiler

© www.soinside.com 2019 - 2024. All rights reserved.