为什么我的结果与微型 asm 示例不同?
Why do my results different following along the tiny asm example?
我正在阅读此页https://www.muppetlabs.com/~breadbox/software/tiny/teensy.html
这是示例之一
; tiny.asm
BITS 32
GLOBAL _start
SECTION .text
_start:
mov eax, 1
mov ebx, 42
int 0x80
Here we go:
$ nasm -f elf tiny.asm
$ gcc -Wall -s -nostdlib tiny.o
$ ./a.out ; echo $?
42
Ta-da! And the size?
$ wc -c a.out
372 a.out
但是我没有得到相同的结果。我尝试了 nasm -f elf64
,然后在 gcc 上尝试了 -m32
(然后又在 clang 上)。无论我尝试什么,我都无法让它变得很小。我在拱门 linux
$ cat tiny.asm
; tiny.asm
BITS 32
GLOBAL _start
SECTION .text
_start:
mov eax, 1
mov ebx, 42
int 0x80
[eric@eric test]$ gcc -Wall -s -nostdlib -m32 tiny.o
[eric@eric test]$ stat ./a.out
File: ./a.out
Size: 12780 Blocks: 32 IO Block: 4096 regular file
Device: 2eh/46d Inode: 1279 Links: 1
Access: (0755/-rwxr-xr-x) Uid: ( 1000/ eric) Gid: ( 1000/ eric)
Access: 2020-12-26 17:19:19.216294869 -0500
Modify: 2020-12-26 17:19:19.216294869 -0500
Change: 2020-12-26 17:19:19.216294869 -0500
Birth: -
-static
不是默认值,即使使用 -nostdlib
,当 GCC 默认配置为制作 PIE 时。 使用gcc -m32 -static -nostdlib
获取历史行为。 (-static
表示 -no-pie
)。有关更多信息,请参阅 。
此外,您可能需要禁用其他部分与 gcc -Wl,--nmagic
的对齐或使用自定义 linker 脚本,并且可能禁用 GCC 添加的额外元数据部分。 Minimal executable size now 10x larger after linking than 2 years ago, for tiny programs?
如果您不link编译任何编译器生成的(来自 C).o
文件,您可能没有 .eh_frame
部分。但如果你是,你可以用 gcc -fno-asynchronous-unwind-tables
禁用它。 (另请参阅 了解旨在查看编译器的 asm 文本输出的一般提示,而不是可执行文件的大小。)
另请参阅 (ndisasm 根本不处理元数据,仅处理平面二进制文件,因此它“反汇编”元数据。因此那里的答案包含有关如何避免其他部分的信息。)
GCC -Wl,--build-id=none
将避免在可执行文件中包含 .note.gnu.build-id
部分。
$ nasm -felf32 foo.asm
$ gcc -m32 -static -nostdlib -Wl,--build-id=none -Wl,--nmagic foo.o
$ ll a.out
-rwxr-xr-x 1 peter peter 488 Dec 26 18:47 a.out
$ strip a.out
$ ll a.out
-rwxr-xr-x 1 peter peter 248 Dec 26 18:47 a.out
(在 x86-64 Arch GNU/Linux、NASM 2.15.05、gcc 10.2、来自 GNU Binutils 2.35.1 的 ld
上测试。)
您可以使用 readelf -a a.out
检查可执行文件中的部分(或使用更具体的选项仅获取 readelf
的一部分输出。)例如在剥离之前,
$ readelf -S unstripped_a.out
...
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 08048060 000060 00000c 00 AX 0 0 16
[ 2] .symtab SYMTAB 00000000 00006c 000070 10 3 3 4
[ 3] .strtab STRTAB 00000000 0000dc 000021 00 0 0 1
[ 4] .shstrtab STRTAB 00000000 0000fd 000021 00 0 0 1
顺便说一句,你肯定不想在使用BITS 32
的文件上使用nasm -felf64
,除非你正在编写内核或其他东西从 64 位长模式切换到 32 位兼容模式。将 32 位机器代码放入 64 位目标文件中没有帮助。只有当你想要原始二进制模式工作时才使用 BITS
(稍后在那个微型 ELF 教程中)。当你从 .o
到 link 时,这只会让你搬起石头砸自己的脚;不要这样做。 (尽管如果您正确使用与 BITS 指令匹配的 nasm -felf32
并无害处。)
我正在阅读此页https://www.muppetlabs.com/~breadbox/software/tiny/teensy.html
这是示例之一
; tiny.asm
BITS 32
GLOBAL _start
SECTION .text
_start:
mov eax, 1
mov ebx, 42
int 0x80
Here we go:
$ nasm -f elf tiny.asm
$ gcc -Wall -s -nostdlib tiny.o
$ ./a.out ; echo $?
42
Ta-da! And the size?
$ wc -c a.out
372 a.out
但是我没有得到相同的结果。我尝试了 nasm -f elf64
,然后在 gcc 上尝试了 -m32
(然后又在 clang 上)。无论我尝试什么,我都无法让它变得很小。我在拱门 linux
$ cat tiny.asm
; tiny.asm
BITS 32
GLOBAL _start
SECTION .text
_start:
mov eax, 1
mov ebx, 42
int 0x80
[eric@eric test]$ gcc -Wall -s -nostdlib -m32 tiny.o
[eric@eric test]$ stat ./a.out
File: ./a.out
Size: 12780 Blocks: 32 IO Block: 4096 regular file
Device: 2eh/46d Inode: 1279 Links: 1
Access: (0755/-rwxr-xr-x) Uid: ( 1000/ eric) Gid: ( 1000/ eric)
Access: 2020-12-26 17:19:19.216294869 -0500
Modify: 2020-12-26 17:19:19.216294869 -0500
Change: 2020-12-26 17:19:19.216294869 -0500
Birth: -
-static
不是默认值,即使使用 -nostdlib
,当 GCC 默认配置为制作 PIE 时。 使用gcc -m32 -static -nostdlib
获取历史行为。 (-static
表示 -no-pie
)。有关更多信息,请参阅
此外,您可能需要禁用其他部分与 gcc -Wl,--nmagic
的对齐或使用自定义 linker 脚本,并且可能禁用 GCC 添加的额外元数据部分。 Minimal executable size now 10x larger after linking than 2 years ago, for tiny programs?
如果您不link编译任何编译器生成的(来自 C).o
文件,您可能没有 .eh_frame
部分。但如果你是,你可以用 gcc -fno-asynchronous-unwind-tables
禁用它。 (另请参阅
另请参阅
GCC -Wl,--build-id=none
将避免在可执行文件中包含 .note.gnu.build-id
部分。
$ nasm -felf32 foo.asm
$ gcc -m32 -static -nostdlib -Wl,--build-id=none -Wl,--nmagic foo.o
$ ll a.out
-rwxr-xr-x 1 peter peter 488 Dec 26 18:47 a.out
$ strip a.out
$ ll a.out
-rwxr-xr-x 1 peter peter 248 Dec 26 18:47 a.out
(在 x86-64 Arch GNU/Linux、NASM 2.15.05、gcc 10.2、来自 GNU Binutils 2.35.1 的 ld
上测试。)
您可以使用 readelf -a a.out
检查可执行文件中的部分(或使用更具体的选项仅获取 readelf
的一部分输出。)例如在剥离之前,
$ readelf -S unstripped_a.out
...
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 08048060 000060 00000c 00 AX 0 0 16
[ 2] .symtab SYMTAB 00000000 00006c 000070 10 3 3 4
[ 3] .strtab STRTAB 00000000 0000dc 000021 00 0 0 1
[ 4] .shstrtab STRTAB 00000000 0000fd 000021 00 0 0 1
顺便说一句,你肯定不想在使用BITS 32
的文件上使用nasm -felf64
,除非你正在编写内核或其他东西从 64 位长模式切换到 32 位兼容模式。将 32 位机器代码放入 64 位目标文件中没有帮助。只有当你想要原始二进制模式工作时才使用 BITS
(稍后在那个微型 ELF 教程中)。当你从 .o
到 link 时,这只会让你搬起石头砸自己的脚;不要这样做。 (尽管如果您正确使用与 BITS 指令匹配的 nasm -felf32
并无害处。)