gpt4 book ai didi

c - GCC 在 x86、win32 上的空程序的汇编输出

转载 作者:太空狗 更新时间:2023-10-29 16:17:45 26 4
gpt4 key购买 nike

我写空程序来惹恼 stackoverflow 编码员,不是。我只是在探索 gnu 工具链。

下面的内容对我来说可能太深了,但为了继续空程序传奇,我已经开始检查 C 编译器的输出,即 GNU 消耗的东西。

gcc version 4.4.0 (TDM-1 mingw32)

测试.c:

int main()
{
return 0;
}

gcc -S test.c

    .file   "test.c"
.def ___main; .scl 2; .type 32; .endef
.text
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
call ___main
movl $0, %eax
leave
ret

你能解释一下这里发生了什么吗?这是我为理解它所做的努力。我使用了 as 手册和我最少的 x86 ASM 知识:

  • .file "test.c" 是逻辑文件名的指令。
  • .def:根据文档“开始为符号名称定义调试信息”。什么是符号(函数名/变量?)以及什么样的调试信息?
  • .scl:文档说 “存储类可能会标记一个符号是静态的还是外部的”。这与我从 C 中了解到的staticexternal 相同吗?那“2”是什么?
  • .type:存储参数“作为符号表条目的类型属性”,我不知道。
  • .endef:没问题。
  • .text:现在这是有问题的,它似乎是一个叫做部分的东西,我已经读到它是代码的地方,但是文档没有告诉我太多。
  • .globl “使符号对 ld 可见。”,手册对此非常清楚。
  • _main:这可能是我的 main 函数的起始地址(?)
  • pushl_:长(32 位)推送,将 EBP 放入堆栈
  • movl:32 位移动。伪 C:EBP = ESP;
  • andl:逻辑与。伪 C:ESP = -16 & ESP,我真的不明白这有什么意义。
  • call:将 IP 插入堆栈(以便被调用的过程可以找到返回的路径)并在 __main 所在的位置继续。 (什么是 __main?)
  • movl:这个零必须是我在代码末尾返回的常量。 MOV 将此零放入 EAX。
  • leave:在 ENTER 指令 (?) 后恢复堆栈。为什么?
  • ret:返回栈中保存的指令地址

感谢您的帮助!

最佳答案

.file "test.c"

以 . 开头的命令。是汇编程序的指令。这只是说这是“file.c”,该信息可以导出到exe的调试信息。

.def ___main; .scl 2; .type 32; .endef

.def 指令定义调试符号。 scl 2 表示存储类 2(外部存储类)。type 32 表示此 sumbol 是一个函数。这些数字将由 pe-coff exe 格式定义

___main 是一个函数,负责 gcc 所需的引导(它将执行诸如运行 c++ 静态初始化程序和其他所需的内务处理之类的事情)。

.text

开始一个文本部分 - 代码位于此处。

.globl _main

将 _main 符号定义为全局符号,这将使它对链接器和其他链接的模块可见。

.def        _main;  .scl    2;      .type   32;     .endef

与 _main 相同,创建调试符号说明 _main 是一个函数。这可供调试器使用。

_main:

开始一个新标签(它将以一个地址结束)。上面的 .globl 指令使该地址对其他实体可见。

pushl       %ebp

将旧的帧指针(ebp 寄存器)保存在堆栈上(以便在该函数结束时可以将其放回原位)

movl        %esp, %ebp

将堆栈指针移动到 ebp 寄存器。 ebp 通常被称为帧指针,它指向当前“帧”(通常是函数)内的堆栈值的顶部,(通过 ebp 引用堆栈上的变量可以帮助调试器)

andl $-16, %esp

然后使用 fffffff0 将堆栈有效地对齐到 16 字节边界上。访问堆栈上对齐的值比访问未对齐的值要快得多。所有这些前面的指令几乎都是标准的函数序言。

call        ___main

调用 ___main 函数来初始化 gcc 需要的东西。 call会将当前指令指针压入栈中,并跳转到___main的地址

movl        $0, %eax

将 0 移动到 eax 寄存器,(返回 0 中的 0;)eax 寄存器用于保存 stdcall 调用约定的函数返回值。

leave

离开指令几乎是

movl     ebp,esp
popl ebp

即它“撤消”了在函数开始时所做的事情——将帧指针和堆栈恢复到它以前的状态。

ret

返回调用此函数的人。它将从堆栈中弹出指令指针(相应的调用指令将放在那里)并跳转到那里。

关于c - GCC 在 x86、win32 上的空程序的汇编输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1317081/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com