Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/55.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
研究一个非常小的C程序的大小_C_Linux_X86_Elf_Strip - Fatal编程技术网

研究一个非常小的C程序的大小

研究一个非常小的C程序的大小,c,linux,x86,elf,strip,C,Linux,X86,Elf,Strip,我正在调查Linux(ubuntu 20.04)上一个非常小的C程序的大小 我的汇编如下: gcc -s -nostdlib test.c -o test 以下程序: __attribute__((naked)) void _start() { asm("movl $1,%eax;" "xorl %ebx,%ebx;" "int $0x80"); } 基本上,我们的想法是让Linux系统调用退出,而不是依赖

我正在调查Linux(ubuntu 20.04)上一个非常小的C程序的大小

我的汇编如下:

gcc -s -nostdlib test.c -o test
以下程序:

__attribute__((naked))
void _start() {
    asm("movl $1,%eax;"
    "xorl %ebx,%ebx;"
    "int  $0x80");
}
基本上,我们的想法是让Linux系统调用退出,而不是依赖C运行时来为我们这样做。(在
void main(){}
中就是这种情况)。程序将1移动到寄存器EAX中,清除寄存器EBX(否则将包含返回值),然后执行linux系统调用中断0x80。这个中断触发内核来处理我们的调用

然而,我希望这个程序非常小(小于1K)

du -h test
# >> 16K
ldd test
# >> statically linked

为什么这个程序仍然是16K?

du
,默认情况下,报告文件在磁盘上使用的空间——这意味着最小值将是一个磁盘块。如果要知道文件的实际大小,请使用
ls-l

du
,默认情况下,报告文件在磁盘上使用的空间--这意味着最小值将是一个磁盘块。如果您想知道文件的实际大小,请使用
ls-l
du
报告文件使用的磁盘空间,而
ls
报告文件的实际大小。通常,对于小文件,
du
报告的大小要大得多

通过更改编译和链接选项以及剥离不必要的部分,可以显著减小二进制文件的大小

$ cat test.c
void _start() {
    asm("movl $1,%eax;"
    "xorl %ebx,%ebx;"
    "int  $0x80");
}

$ gcc -s -nostdlib test.c -o test
$ ./test
$ ls -l test
-rwxrwxr-x 1 fpm fpm 8840 Dec  9 04:09 test

$ readelf -W --section-headers test
There are 7 section headers, starting at offset 0x20c8:

Section Headers:
  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
  [ 1] .note.gnu.build-id NOTE            0000000000400190 000190 000024 00   A  0   0  4
  [ 2] .text             PROGBITS        0000000000401000 001000 000010 00  AX  0   0  1
  [ 3] .eh_frame_hdr     PROGBITS        0000000000402000 002000 000014 00   A  0   0  4
  [ 4] .eh_frame         PROGBITS        0000000000402018 002018 000038 00   A  0   0  8
  [ 5] .comment          PROGBITS        0000000000000000 002050 00002e 01  MS  0   0  1
  [ 6] .shstrtab         STRTAB          0000000000000000 00207e 000045 00      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)
$

$ gcc -s -nostdlib -Wl,--nmagic test.c -o test
$ ls -l test
-rwxrwxr-x 1 fpm fpm 984 Dec  9 16:55 test
$ strip -R .comment -R .note.gnu.build-id test
$ strip -R .eh_frame_hdr -R .eh_frame test
$ ls -l test
-rwxrwxr-x 1 fpm fpm 520 Dec  9 17:03 test
$ 
请注意,在这个特定实例中,
clang
在默认情况下可以生成比
gcc
小得多的二进制文件。但是,在使用
clang
编译并去除不必要的部分后,二进制文件的最终大小是736字节,这比使用
gcc-s-nostlib-Wl,--nmagic test.c-o test
可能的520字节大

$ clang -static -nostdlib -flto -fuse-ld=lld -o test test.c
$ ls -l test
-rwxrwxr-x 1 fpm fpm 1344 Dec  9 04:15 test
$

$ readelf -W --section-headers test
There are 9 section headers, starting at offset 0x300:

Section Headers:
  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
  [ 1] .note.gnu.build-id NOTE            0000000000200190 000190 000018 00   A  0   0  4
  [ 2] .eh_frame_hdr     PROGBITS        00000000002001a8 0001a8 000014 00   A  0   0  4
  [ 3] .eh_frame         PROGBITS        00000000002001c0 0001c0 00003c 00   A  0   0  8
  [ 4] .text             PROGBITS        0000000000201200 000200 00000f 00  AX  0   0 16
  [ 5] .comment          PROGBITS        0000000000000000 00020f 000040 01  MS  0   0  1
  [ 6] .symtab           SYMTAB          0000000000000000 000250 000048 18      8   2  8
  [ 7] .shstrtab         STRTAB          0000000000000000 000298 000055 00      0   0  1
  [ 8] .strtab           STRTAB          0000000000000000 0002ed 000012 00      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)
$ 
  
$ strip -R .eh_frame_hdr -R .eh_frame test
$ strip -R .comment -R .note.gnu.build-id test
strip: test: warning: empty loadable segment detected at vaddr=0x200000, is this intentional?
$ ls -l test
-rwxrwxr-x 1 fpm fpm 736 Dec  9 04:19 test
$ readelf -W --section-headers test
There are 3 section headers, starting at offset 0x220:

Section Headers:
  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
  [ 1] .text             PROGBITS        0000000000201200 000200 00000f 00  AX  0   0 16
  [ 2] .shstrtab         STRTAB          0000000000000000 00020f 000011 00      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)
$ 

.text
是您的代码,
.shstrtab
是节头字符串表。每个
ElfHeader
结构都包含一个
e_shstrndx
成员,该成员是
.shstrtab
表的索引。如果使用此索引,可以找到该节的名称。

du
报告文件使用的磁盘空间,而
ls
报告文件的实际大小。通常,对于小文件,
du
报告的大小要大得多

通过更改编译和链接选项以及剥离不必要的部分,可以显著减小二进制文件的大小

$ cat test.c
void _start() {
    asm("movl $1,%eax;"
    "xorl %ebx,%ebx;"
    "int  $0x80");
}

$ gcc -s -nostdlib test.c -o test
$ ./test
$ ls -l test
-rwxrwxr-x 1 fpm fpm 8840 Dec  9 04:09 test

$ readelf -W --section-headers test
There are 7 section headers, starting at offset 0x20c8:

Section Headers:
  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
  [ 1] .note.gnu.build-id NOTE            0000000000400190 000190 000024 00   A  0   0  4
  [ 2] .text             PROGBITS        0000000000401000 001000 000010 00  AX  0   0  1
  [ 3] .eh_frame_hdr     PROGBITS        0000000000402000 002000 000014 00   A  0   0  4
  [ 4] .eh_frame         PROGBITS        0000000000402018 002018 000038 00   A  0   0  8
  [ 5] .comment          PROGBITS        0000000000000000 002050 00002e 01  MS  0   0  1
  [ 6] .shstrtab         STRTAB          0000000000000000 00207e 000045 00      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)
$

$ gcc -s -nostdlib -Wl,--nmagic test.c -o test
$ ls -l test
-rwxrwxr-x 1 fpm fpm 984 Dec  9 16:55 test
$ strip -R .comment -R .note.gnu.build-id test
$ strip -R .eh_frame_hdr -R .eh_frame test
$ ls -l test
-rwxrwxr-x 1 fpm fpm 520 Dec  9 17:03 test
$ 
请注意,在这个特定实例中,
clang
在默认情况下可以生成比
gcc
小得多的二进制文件。但是,在使用
clang
编译并去除不必要的部分后,二进制文件的最终大小是736字节,这比使用
gcc-s-nostlib-Wl,--nmagic test.c-o test
可能的520字节大

$ clang -static -nostdlib -flto -fuse-ld=lld -o test test.c
$ ls -l test
-rwxrwxr-x 1 fpm fpm 1344 Dec  9 04:15 test
$

$ readelf -W --section-headers test
There are 9 section headers, starting at offset 0x300:

Section Headers:
  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
  [ 1] .note.gnu.build-id NOTE            0000000000200190 000190 000018 00   A  0   0  4
  [ 2] .eh_frame_hdr     PROGBITS        00000000002001a8 0001a8 000014 00   A  0   0  4
  [ 3] .eh_frame         PROGBITS        00000000002001c0 0001c0 00003c 00   A  0   0  8
  [ 4] .text             PROGBITS        0000000000201200 000200 00000f 00  AX  0   0 16
  [ 5] .comment          PROGBITS        0000000000000000 00020f 000040 01  MS  0   0  1
  [ 6] .symtab           SYMTAB          0000000000000000 000250 000048 18      8   2  8
  [ 7] .shstrtab         STRTAB          0000000000000000 000298 000055 00      0   0  1
  [ 8] .strtab           STRTAB          0000000000000000 0002ed 000012 00      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)
$ 
  
$ strip -R .eh_frame_hdr -R .eh_frame test
$ strip -R .comment -R .note.gnu.build-id test
strip: test: warning: empty loadable segment detected at vaddr=0x200000, is this intentional?
$ ls -l test
-rwxrwxr-x 1 fpm fpm 736 Dec  9 04:19 test
$ readelf -W --section-headers test
There are 3 section headers, starting at offset 0x220:

Section Headers:
  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
  [ 1] .text             PROGBITS        0000000000201200 000200 00000f 00  AX  0   0 16
  [ 2] .shstrtab         STRTAB          0000000000000000 00020f 000011 00      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)
$ 

.text
是您的代码,
.shstrtab
是节头字符串表。每个
ElfHeader
结构都包含一个
e_shstrndx
成员,该成员是
.shstrtab
表的索引。如果使用此索引,您可以找到该节的名称。

修改程序以获得等于3的退出代码(为了好玩):

void\u start(){
asm(“movl$1,%eax
“movl$3,%ebx;”
“整$0x80”);
}
此版本包含以下内容:

-s
从可执行文件中删除所有符号表和重定位信息。
-nostlib
链接时不要使用标准系统启动文件或库

$gcc-s-nostdlib pg.c-o pg
美元/页
$echo$?
3.
$ldd./pg
静态链接
生成的可执行文件大小为13 KB:

$ ls -l ./pg
-rwxrwxr-x 1 xxx xxx 13296 dec.   9 11:42 ./pg
代码反汇编显示文本部分实际上有23字节长,并且没有数据:

$objdump-S./pg
./pg:文件格式elf64-x86-64
第节的分解。正文:
0000000000001000 :
1000:f3 0f 1e fa endbr64
1004:55%按需付费
1005:48 89 e5 mov%rsp,%rbp
1008:b8 01 00 mov$0x1,%eax
100d:bb 03 00 mov$0x3,%ebx
1012:cd 80整数$0x80
1014:90不
1015:5d pop%rbp
1016:c3 retq
但是
size
实用程序显示数据部分为224(动态部分的大小),报告的文本大小为248字节。这是其他部分的总大小减去。注释:

$size pg
文本数据bss dec十六进制文件名
24822404721d8页
$size pg--format=SysV
pg:
截面尺寸地址
.interp 28 792
.note.gnu.property 32 824
.note.gnu.build-id 36 856
.gnu.hash 28896
.dynsym 24928
.dynstr 1 952
.文本23 4096
.eh_frame_hdr 20 8192
.eh_帧56 8216
.动态224 16160
.评论42 0
总数514
如果我们重建程序,添加:

-静态
在支持动态链接的系统上,这会覆盖-pie并阻止和共享库的链接。在其他系统上,此选项无效

文件大小减小(8816字节而不是13 KB):

$gcc-s-static-nostlib pg.c-o pg
$ls-l./pg
-RWXR-x 1 xxxx xxxx 8816 12月9日13:03。/pg
“-静态”选项使多个动态链接相关部分消失:

$size pg
文本数据bss dec十六进制文件名
1470 0 147 93页
$size pg--format=SysV
pg:
截面尺寸地址
.note.gnu.property 32 4194760
.note.gnu.build-id 36 4194792
.文本234198400
.eh_帧56 4202496
.评论