简单的 hello world exec 是 10 KB

Posted

技术标签:

【中文标题】简单的 hello world exec 是 10 KB【英文标题】:simple hello world exec is 10 kilobytes 【发布时间】:2019-03-14 09:44:05 【问题描述】:

我在 x86 nasm 汇编中做了一个简单的 Hello World 程序,但我不明白为什么最终的 exec 几乎是 10Ko。

nasm 版本:

NASM 版本 2.13.03 于 2018 年 4 月 1 日编译

ld 版本:

GNU ld (GNU Binutils) 2.31.1

这是我的源代码:

    ; -------------------------------------------------------------
; Writes "Hello, World" to the console using only system calls.
; Runs on 64-bit Linux only.
; To assemble and run:
;
;     nasm -f elf64 hello.asm
;     ld hello.o -o hello
;     ./hello
;     or in one line
;     nasm -felf64 hello.asm && ld hello.o -o hello && ./hello
;
; -------------------------------------------------------------

%define newline 0xA
%define nullchar 0x0

%define SYS_WRITE 1 ; system callcode for write
%define SYS_EXIT 60 ; system callcode for exit

%define STD_OUT 1

section   .data
    message  db    "Hello, World!", newline, nullchar
    len_message  equ  $-message

section   .text
;we must export the entry point to the ELF linker or
;loader. They conventionally recognize _start as their
;entry point. Use ld -e foo to override the default.
global  _start

_start:
    call .print
    call .exit

.print:
    mov       rax, SYS_WRITE
    mov       rdi, STD_OUT            ; we write text in the shell
    mov       rsi, message            ; address of string to output
    mov       rdx, len_message        ; number of bytes
    syscall                           ; invoke kernel
    ret                               ; return

.exit:
    mov       rax, SYS_EXIT
    mov       rdi, 0                  ; exit code 0
    syscall                           ; invoke kernel

当我用 nasm -f elf64 hello.asm 组装它时, 我得到一个大小为 976 字节的 hello.o 文件。

当我将它与 ld hello.o -o hello 链接时, 我得到一个大小为 8.9K 的 hello exec(我用 ls -lh 得到大小)。

为什么链接会使最终的 exec 如此庞大?即使我使用删除调试数据的选项 (ld -s),我也只会丢失 500 个字节。

这是来自

的输出
readelf -a hello

ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x401000
  Start of program headers:          64 (bytes into file)
  Start of section headers:          8656 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         4
  Size of section headers:           64 (bytes)
  Number of section headers:         7
  Section header string table index: 6

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .note.gnu.propert NOTE             0000000000400120  00000120
       0000000000000020  0000000000000000   A       0     0     8
  [ 2] .text             PROGBITS         0000000000401000  00001000
       0000000000000032  0000000000000000  AX       0     0     16
  [ 3] .data             PROGBITS         0000000000402000  00002000
       000000000000000f  0000000000000000  WA       0     0     4
  [ 4] .symtab           SYMTAB           0000000000000000  00002010
       0000000000000138  0000000000000018           5     9     8
  [ 5] .strtab           STRTAB           0000000000000000  00002148
       0000000000000048  0000000000000000           0     0     1
  [ 6] .shstrtab         STRTAB           0000000000000000  00002190
       000000000000003a  0000000000000000           0     0     1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  l (large), p (processor specific)

There are no section groups in this file.

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  LOAD           0x0000000000000000 0x0000000000400000 0x0000000000400000
                 0x0000000000000140 0x0000000000000140  R      0x1000
  LOAD           0x0000000000001000 0x0000000000401000 0x0000000000401000
                 0x0000000000000032 0x0000000000000032  R E    0x1000
  LOAD           0x0000000000002000 0x0000000000402000 0x0000000000402000
                 0x000000000000000f 0x000000000000000f  RW     0x1000
  NOTE           0x0000000000000120 0x0000000000400120 0x0000000000400120
                 0x0000000000000020 0x0000000000000020  R      0x8

 Section to Segment mapping:
  Segment Sections...
   00     .note.gnu.property 
   01     .text 
   02     .data 
   03     .note.gnu.property 

There is no dynamic section in this file.

There are no relocations in this file.

The decoding of unwind sections for machine type Advanced Micro Devices X86-64 is not currently supported.

Symbol table '.symtab' contains 13 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000400120     0 SECTION LOCAL  DEFAULT    1 
     2: 0000000000401000     0 SECTION LOCAL  DEFAULT    2 
     3: 0000000000402000     0 SECTION LOCAL  DEFAULT    3 
     4: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS hello.asm
     5: 0000000000402000     0 NOTYPE  LOCAL  DEFAULT    3 message
     6: 000000000000000f     0 NOTYPE  LOCAL  DEFAULT  ABS len_message
     7: 000000000040100a     0 NOTYPE  LOCAL  DEFAULT    2 _start.print
     8: 0000000000401026     0 NOTYPE  LOCAL  DEFAULT    2 _start.exit
     9: 0000000000401000     0 NOTYPE  GLOBAL DEFAULT    2 _start
    10: 000000000040200f     0 NOTYPE  GLOBAL DEFAULT    3 __bss_start
    11: 000000000040200f     0 NOTYPE  GLOBAL DEFAULT    3 _edata
    12: 0000000000402010     0 NOTYPE  GLOBAL DEFAULT    3 _end

No version information found in this file.

Displaying notes found in: .note.gnu.property
  Owner                 Data size   Description
  GNU                  0x00000010   NT_GNU_PROPERTY_TYPE_0
      Properties: x86 ISA needed: i486

【问题讨论】:

您的设置或默认设置有问题。在我的系统上,剥离后得到 1043 字节或 528 字节。使用readelf 查看包含的内容。即使使用-pie,我也只能得到 2152 个字节。或者,算了吧,谁在乎呢?它不会与任何更大的程序相关。 这里很好地解释了对象和编译文件如何在不同的编译器上工作,无论是否剥离。讲座愉快:resources.infosecinstitute.com/… 这个和padding有关;二进制文件中的每个段都被填充到 4 kB 以启用内存保护。您可以使用自定义链接器脚本解决此问题,但这并不值得。 您使用的是什么 NASM 和 ld 版本? edit 你的问题与ld --version 的输出。 (并将您的 readelf 输出放在问题中,而不是作为答案。)我得到类似于 Jester 的结果;即使使用nasm -felf64 -g -Fdwarf 添加调试信息,未剥离的二进制文件也只有 2.1k。链接器将文件中的部分打包在一起,并将它们映射到与文件偏移量匹配的起始地址。 @MichaelPetch 我在 ArchLinux 上 【参考方案1】:

我想我找到了一些东西。

在 ld 的 2.30 版本中,添加了一个新标志并默认激活

2.30 的变化:

添加 -z separate-code 生成单独的代码 PT_LOAD 段。

source

如果我链接到ld -z noseparate-code hello.o -o hello

二进制的大小为1032字节,比较合理。 我不知道 PT_LOAD 是什么,但运行 hello world 程序看起来并不重要。

【讨论】:

在 readelf 输出中,请注意“程序头”列表中有三个 Type = LOAD 的段。这些是PT_LOAD 段。此更改可确保文本和数据段的映射之间没有重叠。很好的发现,这确实完美地解释了您所看到的 0x1000 (4096) 对齐和段之间的偏移。

以上是关于简单的 hello world exec 是 10 KB的主要内容,如果未能解决你的问题,请参考以下文章

如何使 .NET 6.0 Hot Reload 在最简单的“Hello, World”控制台应用程序上工作?

exec与eval函数的使用

如何制作“Hello world”内核

macos GCC工具链编译简单的hello world的问题[重复]

Python中的execeval的区别

c++入门题~太简单啦——输出“Hello World!”