Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/71.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.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_Gcc_X86 64_Disassembly - Fatal编程技术网

C 编译器:理解小程序生成的汇编代码

C 编译器:理解小程序生成的汇编代码,c,linux,gcc,x86-64,disassembly,C,Linux,Gcc,X86 64,Disassembly,我正在自学编译器的工作原理。我通过阅读小型64位Linux程序中GCC生成代码的反汇编来学习 我写了这个C程序: #包括 int main() { 对于(int i=0;i关于第二个问题,由于C99标准不允许在main函数中有显式返回0,编译器将隐式添加它。请注意,这仅适用于main函数,没有其他函数 至于第三个问题,rbp登记册充当第一个问题 最后是PS。被调用函数很可能正在使用16字节(0x10)作为传递给函数的参数。减法就是从堆栈中“删除”这些变量的方法。它可能是作为参数传递的两个指针吗

我正在自学编译器的工作原理。我通过阅读小型64位Linux程序中GCC生成代码的反汇编来学习

我写了这个C程序:

#包括
int main()
{

对于(int i=0;i关于第二个问题,由于C99标准不允许在
main
函数中有显式
返回0
,编译器将隐式添加它。请注意,这仅适用于
main
函数,没有其他函数

至于第三个问题,
rbp
登记册充当第一个问题

最后是PS。被调用函数很可能正在使用
16
字节(
0x10
)作为传递给函数的参数。减法就是从堆栈中“删除”这些变量的方法。它可能是作为参数传递的两个指针吗


如果您正在认真学习编译器的一般工作原理,并且可能希望创建自己的编译器(这很有趣!),那么我建议你投资一些关于it理论和实践的书籍。这是程序员书架上的一个极好的补充。

ret
之后的任何东西都不能被依赖为代码。解码为
nop
意味着“无操作”

第二点是编译器检测到您离开
main
函数而不返回值,并插入
return0
(仅为
main
定义)

rbp
寄存器,其中
bp
表示“基指针”,指向currect函数的堆栈帧。函数调用通常会导致函数条目保存
rbp
,并将当前值
rsp
用于
rbp
。获取/存储函数参数和局部变量是相对于
rbp
完成的。
我认为您的第三个问题需要更多关注,“为什么编译器不在堆栈上用
子rsp,0x10
分配空间?为什么不使用rbp寄存器引用本地堆栈数据?”

实际上,编译器确实在堆栈上分配了空间。但它不会更改堆栈指针。它可以这样做,因为函数不调用其他函数。它只使用当前
sp
(堆栈变小)下的空间,并使用
rbp
访问
i
[rbp-0x8]
)和
k
[rbp-0x4]
)。
我必须补充以下注意事项:不调整
sp
以使用局部变量似乎不是中断安全的,因此编译器依赖硬件在中断发生时自动切换到系统堆栈。否则,出现的第一个中断会将指令指针推到堆栈上,并覆盖loc变量

中断问题解决于

  • 是的,nop是用于对齐的。编译器使用不同的指令进行不同长度的填充,知道现代CPU将提前预取和解码多条指令

  • 正如其他人所说,如果没有显式的return语句(请参见中的5.1.2.2.3),C99标准默认情况下会从main()返回0,因此不会发出警告

  • 在当前堆栈指针下保留一个128字节的“红色区域”,叶函数(不调用任何其他函数的函数-main()就是这样一个函数)可以将其用于局部变量和其他临时值,而无需子rsp/添加rsp。因此rbp==rsp


  • 对于PS:当您在for()循环(或main()中的任何位置)中调用函数时,main()不再是叶函数,因此编译器不能再使用红色区域。这就是它在堆栈上分配空间的原因,子rsp为0x10。但是,它知道rsp和rbp之间的关系,因此在访问数据时可以使用两者。

    加1/3整数arithmetic@Bathsheba我甚至没想到会有那么多!:)邓尼,也许吧“为什么我们不能有一个合理的投票数类型"这是一个元问题吗?因为我们不希望upvots从3变为2.99999997,所以有一点提示:如果你想玩编译器,请检查:没有一个答案真正抓住了#3出现的原因。你可以在Linux 64位代码中找到这一点。编译器正在利用。你可以在。中找到这个红色区域的信息文件回顾第3.2.2节:堆栈框架的py。由于您的函数是叶函数(不调用其他函数),它可以利用以下事实,即当前RSP下128字节不会被信号处理等破坏,因为RSP(叶函数中)的当前值下128字节如果基于堆栈的函数数据可以容纳128字节,则无需调整RSP。这就是为什么您在这里看不到调整的RSP。一个观察结果。在32位Linux中不存在红色区域,因此编译为32位代码时,您应该会看到您可能预期的行为。至于添加
    测试时为什么会出现问题ode>函数编译器减去16个字节,尽管需要更少的字节与64位Linux ABI要求有关,即在任何函数调用(如调用
    test
    )时,堆栈需要16个字节(可能32个字节对齐)。由于堆栈在调用点对齐,因此调用本身将推送8字节的返回地址。这将使堆栈偏移8。
    push rbp
    减去另一个8,使其再次对齐16字节。现在需要局部变量数据。编译器通常通过减去16字节来分配足够的字节以保持16字节的对齐,b当它到达调用
    test
    时,堆栈保持16字节对齐,一切正常。在ret调用之后,编译器只抛出随机操作码?@Ofey:这里的任何答案都没有捕捉到NOP存在的原因。在大多数情况下,当它位于函数之后(在本例中为
    ret
    之后),它已放置在那里,以便下一个f
    #include <stdio.h>
    
    int main()
    {
        for(int i=0;i<10;i++){
            int k=0;
        }
    }
    
    00000000004004d6 <main>:
      4004d6:       55                      push   rbp
      4004d7:       48 89 e5                mov    rbp,rsp
      4004da:       c7 45 f8 00 00 00 00    mov    DWORD PTR [rbp-0x8],0x0
      4004e1:       eb 0b                   jmp    4004ee <main+0x18>
      4004e3:       c7 45 fc 00 00 00 00    mov    DWORD PTR [rbp-0x4],0x0
      4004ea:       83 45 f8 01             add    DWORD PTR [rbp-0x8],0x1
      4004ee:       83 7d f8 09             cmp    DWORD PTR [rbp-0x8],0x9
      4004f2:       7e ef                   jle    4004e3 <main+0xd>
      4004f4:       b8 00 00 00 00          mov    eax,0x0
      4004f9:       5d                      pop    rbp
      4004fa:       c3                      ret    
      4004fb:       0f 1f 44 00 00          nop    DWORD PTR [rax+rax*1+0x0]