【问题标题】:Why do my results different following along the tiny asm example?为什么我的结果与微小的 asm 示例不同?
【发布时间】:2021-04-04 06:11:46
【问题描述】:

我正在阅读此页面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 上)。无论我尝试什么,我都无法让它变得很小。我在 Arch 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: -

【问题讨论】:

  • 发布objdump -d a.out 的输出。但我怀疑这与添加到 a.out 的不同页面有关,这些页面可能并不总是使用不同的工具或在不同的发行版上生成。有些事情可能是 - 展开 .eh_frame 部分中的表格、构建注释、cmets 以及对齐方式的变化。

标签: linux assembly gcc x86-64 nasm


【解决方案1】:

-static 不是默认值,即使使用-nostdlib,当 GCC 被配置为默认制作 PIE 时。 使用gcc -m32 -static -nostdlib 获取历史行为。 (-static 暗示 -no-pie)。请参阅What's the difference between "statically linked" and "not a dynamic executable" from Linux ldd? 了解更多信息。

此外,您可能需要禁用其他部分与gcc -Wl,--nmagic 或使用自定义链接器脚本的对齐,并且可能需要禁用 GCC 添加的元数据的额外部分。 Minimal executable size now 10x larger after linking than 2 years ago, for tiny programs?

如果您没有链接任何编译器生成的(从 C 语言).o 文件,您可能没有 .eh_frame 部分。但如果您是,您可以使用gcc -fno-asynchronous-unwind-tables 禁用它。 (另请参阅How to remove "noise" from GCC/clang assembly output? 以获得旨在查看编译器的 asm 文本输出的一般提示,而不是可执行文件大小。)

另请参阅GCC + LD + NDISASM = huge amount of assembler instructions(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、ld 来自 GNU Binutils 2.35.1 上测试。)


您可以使用 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(稍后在该 tiny-ELF 教程中)。当您创建.o 链接时,它只会让您有可能在脚下开枪;不要这样做。 (尽管如果您正确使用与您的 BITS 指令匹配的nasm -felf32,它不会有害。)

【讨论】:

  • 您忘记了其他内容,例如异步展开表(在 .eh_frame 部分中)、构建说明和 cmets 部分。询问这个人他们生成了哪些部分和代码可能会告诉我们为什么它是 12k。您在这里提出的建议可能只涉及冰山一角。几个月前我们在这里遇到过类似的问题:stackoverflow.com/questions/62775154/…。构建说明将是使用 GCC 和 LD 的产物。我怀疑-Wl,--build-id=non 可能有助于将 GCC 用作 LD 的前端。
  • @MichaelPetch:我已经在更新我对.eh_frame 的回答——只有在链接 C 编译器输出时才能得到。我刚刚在我的桌面上尝试过:我确实得到了.note.gnu.build-id。但这应该与 OP 所遵循的教程相匹配,该教程移至strip,然后移至手动生成的 ELF 程序头,然后将文本段塞入这些头中:P
  • 查看我的编辑我展示了如何摆脱 build-ide 。 cmets 部分只能通过objcopy 之类的方式移除。但我猜测可能已经生成的所有潜在部分。据我所知,Strip 并没有删除所有部分,例如.comments。我想我在过去 30 天里也对这个主题的一个更新的问题发表了评论。
  • @MichaelPetch:谢谢,更新了示例输出。
  • 使用 64 位为我工作,它到达 704 字节
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-03
  • 1970-01-01
  • 2021-07-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多