You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何创建小于4097字节的Linux i386 a.out可执行文件?

如何创建小于4097字节的Linux i386 a.out可执行文件

现状与测试环境

我尝试创建一个小于4097字节的Linux i386 a.out可执行文件,但所有尝试均失败。

编译命令:

$ nasm -O0 -f bin -o prog prog.nasm && chmod +x prog

测试环境为运行Linux 2.6.32的Ubuntu 10.04 i386虚拟机,测试步骤:

$ sudo modprobe binfmt_aout
$ sudo sysctl vm.mmap_min_addr=4096
$ ./prog; echo $?
Hello, World!
0

当前可正常运行的4097字节源码:

; prog.nasm
        bits 32
        cpu 386
        org 0x1000  ; Linux i386 a.out QMAGIC file format has this.

SECTION_text:
a_out_header:
        dw 0xcc  ; magic=QMAGIC; Demand-paged executable with the header in the text. The first page (0x1000 bytes) is unmapped to help trap NULL pointer references.
        db 0x64  ; type=M_386
        db 0  ; flags=0
        dd SECTION_data - SECTION_text  ; a_text=0x1000 (byte size of .text; mapped as r-x)
        dd SECTION_end - SECTION_data  ; a_data=0x1000 (byte size of .data; mapped as rwx, not just rw-)
        dd 0  ; a_bss=0 (byte size of .bss)
        dd 0  ; a_syms=0 (byte size of symbol table data)
        dd _start  ; a_entry=0x1020 (in-memory address of _start == file offset of _start + 0x1000)
        dd 0  ; a_trsize=0 (byte size of relocation info or .text)
        dd 0  ; a_drsize=0 (byte size of relocation info or .data)

_start:     mov eax, 4              ; __NR_write
        mov ebx, 1              ; argument: STDOUT_FILENO
        mov ecx, msg            ; argument: address of string to output
        mov edx, msg_end - msg  ; argument: number of bytes
        int 0x80                ; syscall

        mov eax, 1              ; __NR_exit
        xor ebx, ebx            ; argument: EXIT_SUCCESS == 0.
        int 0x80                ; syscall

msg:        db 'Hello, World!', 10
msg_end:

        times ($$ - $) & 0xfff db 0  ; padding to multiple of 0x1000  ; !! is this needed?
SECTION_data:   db 0
;       times ($$ - $) & 0xfff db 0  ; padding to multiple of 0x1000  ; !! is this needed?
SECTION_end:

已发现的限制规则

  • a_text或a_data为0时,Linux无法运行程序
  • a_text必须是0x1000(4096)的倍数,否则无法运行
  • 文件大小必须大于等于a_text + a_data,否则无法运行

由此推导文件大小下限为0x1000 + 1 = 4097字节。

尝试过用nasm -f aout+ld -s -m i386linux、nasm -f elf+ld -s -m i386linux、as -32+ld -s -m i386linux组合生成的4100字节文件无法运行(因a_data为0),给.data段加1字节后文件变为8196字节才能运行,此路径无法得到更小的文件。

问题

是否遗漏了什么?能否做出更小的Linux i386 a.out可执行文件?


解答

结论:无法突破4097字节的下限

根据你总结的Linux内核对a.out格式的校验规则,4097字节确实是QMAGIC格式a.out可执行文件的最小合法大小,原因如下:

  1. QMAGIC格式要求a_text必须是页面大小(0x1000)的倍数,且不能为0
  2. a_data不能为0,最小为1字节
  3. 文件总大小必须至少等于a_text + a_data,即4096+1=4097字节

优化当前代码的小细节

虽然无法突破大小下限,但可以优化源码里的冗余部分,让代码更简洁精准:

  • 直接指定a_text为0x1000、a_data为1,避免计算偏移的冗余
  • 精准计算.text段需要填充的字节数,避免模糊的位运算填充

修改后的最小化源码:

; prog_min.nasm
bits 32
cpu 386
org 0x1000

SECTION_text:
a_out_header:
        dw 0xcc          ; QMAGIC标识
        db 0x64          ; M_386架构类型
        db 0             ; 无特殊标志
        dd 0x1000        ; a_text = 4096字节(页大小倍数,必须非0)
        dd 1             ; a_data = 1字节(最小非0值)
        dd 0             ; 无BSS段
        dd 0             ; 无符号表
        dd _start        ; 程序入口地址
        dd 0             ; 无代码段重定位信息
        dd 0             ; 无数据段重定位信息

_start:
        mov eax, 4       ; 系统调用号__NR_write
        mov ebx, 1       ; 参数:标准输出STDOUT_FILENO
        mov ecx, msg
        mov edx, msg_len
        int 0x80

        mov eax, 1       ; 系统调用号__NR_exit
        xor ebx, ebx     ; 参数:退出码0(成功)
        int 0x80

msg:    db 'Hello, World!', 10
msg_len equ $ - msg

; 填充.text段至4096字节
times 0x1000 - ($ - SECTION_text) db 0
SECTION_data: db 0  ; 1字节数据段,满足a_data非0要求
SECTION_end:

编译后文件大小正好是4097字节,运行效果与原代码完全一致。

为什么链接器生成的文件更大?

用ld链接生成a.out时,默认会把.data段强制对齐到页大小(4096字节),所以即使只添加1字节数据,也会被填充到4096字节,导致总大小达到8192字节。而手动编写bin格式的a.out可以绕过这种强制对齐,仅给.data段保留1字节,从而达到理论最小大小。


内容的提问来源于stack exchange,提问作者pts

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 12:10:45