GAS 组装的 QEMU 中 ARM64 ELF 可执行文件 运行 的对齐要求

alignment requirements for ARM64 ELF executables run in QEMU assembled by GAS

我有这个 ARM64 程序,当我 运行 它时,它会立即汇编但会出现段错误:

// GNU Assembler, ARM64 Linux

.bss

.lcomm ARRAY, 16

.text

.global _start

_start:
    mov x8, 93 // exit sys num
    mov x0, 0 // success
    svc 0

通过暴力试验和错误,我设法通过添加以下行来修复它:

// GNU Assembler, ARM64 Linux

.bss

.lcomm ARRAY, 16

.p2align 12 // why?

.text

.global _start

_start:
    mov x8, 93 // exit sys num
    mov x0, 0 // success
    svc 0

它只适用于 .p2align 12(相当于 .balign 4096)或更高的值,否则它仍然会在 .p2align 11 或更低的值下出现段错误。我知道填充可能会解决一些错位问题,但我不明白为什么它必须是这么大的值,因为我见过的几乎所有其他 ARM64 示例,无论是手写的还是由编译器生成的,通常都只插入一个.p2align 2.text 部分之前,为什么我的小程序需要 .p2align 12

此外,我注意到所需的填充大小与 .text 部分的长度成反比。对于像上面这样的小程序,.p2align 12 需要使它们成为 运行 而不会出现段错误,但是 .text 部分越长,我可以做的填充就越小,对于有数千个的程序说明我根本不需要添加任何填充!

我在 x86_64 macOS 机器上,但我正在 运行 将这些程序编译到一个 Docker 容器中,该容器是从这个 Docker 构建的文件:

FROM ubuntu:20.04
RUN apt-get update && apt-get -y install clang qemu gcc-aarch64-linux-gnu

我正在编译和运行使用 ARM64 程序:

clang -nostdlib -fno-integrated-as -target aarch64-linux-gnu -s program.s -o program.out && ./program.out

我觉得我遗漏了一些关于 GAS、QEMU、ARM64 或 ELF 可执行文件的重要信息,但我不知道它是什么。

QEMU 对您的数据部分的程序头感到困惑:

    LOAD off    0x00000000000000c0 vaddr 0x00000000004100c0 paddr 0x00000000004100c0 align 2**16
         filesz 0x0000000000000000 memsz 0x0000000000000010 flags rw-

并且无法在该地址实际映射一些可写内存;段错误来自 QEMU 本身,当它试图将 BSS 的 memset() 设置为零时。

由于程序在真正的 AArch64 Linux 内核上运行良好,这是一个 QEMU 错误。我已经报告了它 to the upstream mailing list 所以我们会看看是否有人提出了解决方案。