在对 tiny ELF 可执行文件进行一些受许多有趣 文章启发的实验时,我注意到 GNU 的
ld
在使用 nasm
生成的 .o
目标文件或使用(GNU)as
生成的一个,都使用(我认为是 1)等效的汇编源。
¹:它们的目标文件仅在非代码部分有所不同,并且如果我strip --strip-section-headers *.o
,则“按位相同”,所以我相信这是一个公平的假设。
(v2.16.1):
; tiny-nasm.asm
SECTION .text
GLOBAL _start
_start:
mov eax, 60 ; Select the _exit syscall (60 in Linux ABI)
mov edi, 42 ; Set the exit code argument for _exit
syscall ; Perform the selected syscall
(v2.42):
# tiny-gas.S
.SECTION .text
.GLOBL _start
_start:
mov $60, %eax # Select the _exit syscall (60 in Linux ABI)
mov $42, %edi # Set the exit code argument for _exit
syscall # Perform the selected syscall
nasm -f elf64 tiny-nasm.asm && ld -no-pie -z noseparate-code tiny-nasm.o -o tiny-nasm.bin
as tiny-gas.S -o tiny-gas.o && ld -no-pie -z noseparate-code tiny-gas.o -o tiny-gas.bin
strip --strip-section-headers *.bin
wc -c *.bin
diff -u <(readelf -Wa tiny-nasm.bin) <(readelf -Wa tiny-gas.bin)
132 tiny-gas.bin
140 tiny-nasm.bin
272 total
--- /dev/fd/63 2024-11-26 02:56:40.248293325 -0300
+++ /dev/fd/62 2024-11-26 02:56:40.248293325 -0300
@@ -8,7 +8,7 @@
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
- Entry point address: 0x400080
+ Entry point address: 0x400078
Start of program headers: 64 (bytes into file)
Start of section headers: 0 (bytes into file)
Flags: 0x0
@@ -25,7 +25,7 @@
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
- LOAD 0x000000 0x0000000000400000 0x0000000000400000 0x00008c 0x00008c R E 0x1000
+ LOAD 0x000000 0x0000000000400000 0x0000000000400000 0x000084 0x000084 R E 0x1000
There is no dynamic section in this file.
两个二进制文件的工作方式相同且符合预期,它们的唯一
区别是ld
选择的入口点地址偏移量,它占文件大小,
as
小8个字节。
为什么ld
ld
选择的不同入口点地址?
如果相关:Ubuntu 24.04、Linux 桌面 6.8.0-48 x86_64、binutils 2.42、AMD Ryzen 5 5700G
section .text
的默认属性是 section .text progbits alloc exe nowrite align=16
。
显然气体的对齐程度较低,低于或等于 8,所以这就是您观察到差异的方式。解决方案是在
align=1
指令中指定 section
属性,如下所示:
section .text align=1