g++二进制输出分析

g++ binary output analysis

本文关键字:输出 二进制 g++      更新时间:2023-10-16

给定以下程序:

unsigned char g1[] = { 0x1a, 0x2a, 0x3a, 0x4a };
static unsigned char g2[] = { 0x1b, 0x2b, 0x3b, 0x4b };
int main()
{
  unsigned char l1[] = { 0x1c, 0x2c, 0x3c, 0x4c };
  static unsigned char l2[] = { 0x1d, 0x2d, 0x3d, 0x4d };
}

之后,简单地用"g++ test.cpp -o test"编译它,并在二进制文件上运行hexdump -C,我意识到g1, g2和l2的序列可以在二进制文件上清晰地找到。只有l1 (1c 2c 3c 4c)的序列在二进制文件中显然没有出现。

有人知道这是为什么吗?

因为它是在该函数调用的堆栈上分配的。通常在这种情况下,会发生以下两种情况之一:

  1. 编译器将该序列存储在数据段中,然后基本上将其memcpy到堆栈缓冲区中。

  2. 编译器本质上是硬编码"move"指令,从指令集(通常是4字节整型)的最大直接值重新组装序列。

如果它没有被优化,就像前面提到的"unwind"一样,那么#2可能会发生。看看反汇编程序(或预汇编的asm代码)会更好。使用-S并查看.s文件。

我的猜测是,因为它是非static和自动的(非全局的),所以知道没有人能够从外部引用它是微不足道的。

l1[]l2[]在编译器优化期间被删除,因为它们都是local and unused variables(没有机会这两个变量将在其他任何地方使用)。

你可以用-S选项编译你的代码来生成汇编代码:并且在main中没有l1[]l2[]的定义,甚至在其他任何地方都没有:

输入文件为x.c,用gcc -S x.c命令编译生成汇编文件x.s

main:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $16, %esp
    movb    $28, -4(%ebp)
    movb    $44, -3(%ebp)
    movb    $60, -2(%ebp)
    movb    $76, -1(%ebp)
    leave
    ret
    .size   main, .-main
    .data
    .type   l2.1250, @object
    .size   l2.1250, 4

但是你可以找到g1[] and g2[]的定义。

    .file   "x.c"
.globl g1
    .data
    .type   g1, @object
    .size   g1, 4
g1:
    .byte   26
    .byte   42
    .byte   58
    .byte   74
    .type   g2, @object
    .size   g2, 4
g2:
    .byte   27
    .byte   43
    .byte   59
    .byte   75
    .text
.globl main
    .type   main, @function  

另外,如果你用标志-O3 优化标志级别3编译你的代码,那么只有g1[]的定义是存在的,这将是有趣的。全局静态变量(文件私有)也被删除。

输入文件为x.c,用gcc -S -O3 x.c命令编译生成汇编文件x.s

:

    .file   "x.c"
    .text
    .p2align 4,,15
.globl main
    .type   main, @function
main:
    pushl   %ebp
    movl    %esp, %ebp
    popl    %ebp
    ret
    .size   main, .-main
.globl g1
    .data
    .type   g1, @object
    .size   g1, 4
g1:
    .byte   26
    .byte   42
    .byte   58
    .byte   74
    .ident  "GCC: (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5"
    .section    .note.GNU-stack,"",@progbits  

g1[]是仅存在的全局数据,g2[]-O3中被删除。

g2[]使用已定义的static unsigned char g2[],所以只能访问这个文件,不能再次使用。但是g1[]是全局的,如果其他文件包含它,它可能对其他程序有用。编译器不允许优化全局对象。

参考:我如何防止我的"未使用的"全局变量被编译出来?

所以,这都是由于编译器优化!