gpt4 book ai didi

c - 了解简单 C 程序的汇编

转载 作者:太空宇宙 更新时间:2023-11-04 03:37:59 25 4
gpt4 key购买 nike

我试图理解这个简单的 C 程序的汇编。

#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
#include<string.h>
void foobar(char *a){
char c = a[0];
}
int main(){
int fd = open("file.txt", O_RDONLY);
char buf1[100]="\0";
char buf[100];
int aa=0,b=1,c=2,d=3,f=2,g=3;
read(fd,buf1,104);
if(strlen(buf1) > 100){

}else{
strcpy(buf,buf1);
}
//strcpy(buf,buf1);
foobar(buf1);
}

我得到的使用 gdb 的可执行文件的反汇编是 foobar 反汇编。

   0x000000000040067d <+0>: push   rbp
0x000000000040067e <+1>: mov rbp,rsp
0x0000000000400681 <+4>: mov QWORD PTR [rbp-0x18],rdi
0x0000000000400685 <+8>: mov rax,QWORD PTR [rbp-0x18]
0x0000000000400689 <+12>: movzx eax,BYTE PTR [rax]
0x000000000040068c <+15>: mov BYTE PTR [rbp-0x1],al
0x000000000040068f <+18>: pop rbp

foobar 之前的主要反汇编

   0x0000000000400784 <+243>:   lea    rax,[rbp-0xf0]
0x000000000040078b <+250>: mov rdi,rax
0x000000000040078e <+253>: call 0x40067d <foobar>
0x0000000000400793 <+258>: mov rbx,QWORD PTR [rbp-0x18]
0x0000000000400797 <+262>: xor rbx,QWORD PTR fs:0x28
0x00000000004007a0 <+271>: je 0x4007a7 <main+278>
0x0000000000400690 <+19>: ret

现在,我有一个关于foobar反汇编的问题

0x0000000000400681 <+4>:    mov    QWORD PTR [rbp-0x18],rdi
0x0000000000400685 <+8>: mov rax,QWORD PTR [rbp-0x18]

不是指令

mov rax, rdi

会做上面两条指令要求的工作。为什么要为 rdi 使用额外的内存位置 rbp - 0x18 ?与引用传递有关吗?

编辑:我想问的另一个问题是为什么 foobar 函数正在访问不在 foobar 框架中的(rbp - 0x18)。?

我的gcc版本是gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2

编辑:在编译时使用 -O1 -O2 和 -O3 优化标志后,foobar 程序集变为

   0x0000000000400670 <+0>: repz ret 

并且在使用 -O3 标志时,一些 main 的反汇编是

   0x0000000000400551 <+81>:    rep stos QWORD PTR es:[rdi],rax
0x0000000000400554 <+84>: mov DWORD PTR [rdi],0x0
0x000000000040055a <+90>: mov cl,0x64
0x000000000040055c <+92>: mov edi,r8d
0x000000000040055f <+95>: call 0x4004b0 <__read_chk@plt>
0x0000000000400564 <+100>: mov rdx,QWORD PTR [rsp+0x68]
0x0000000000400569 <+105>: xor rdx,QWORD PTR fs:0x28
0x0000000000400572 <+114>: jne 0x400579 <main+121>
0x0000000000400574 <+116>: add rsp,0x78
0x0000000000400578 <+120>: ret
0x0000000000400579 <+121>: call 0x4004c0 <__stack_chk_fail@plt>

我在 main 中找不到任何对 foobar 的调用。

最佳答案

这是个好问题。可以这么说,我赞扬您“窥视幕后”。

大量研究已进入编译代码。有时你希望代码运行得快,有时你希望它小,有时你希望它编译得快。由于编译器的研究,编译器可以生成以上述任何方式运行的代码。为了允许用户选择他们想要的这些选项中的哪一个,gcc 有 command line options that control the level of optimization .

默认情况下,gcc 使用-O0,它不会对代码进行太多优化,而是专注于最快的编译时间。因此,您有时会发现效率低下的指令序列。


当您打开 -O3 标志时,编译器内联 foobar 的代码。如您所知,函数调用需要时间,因此,如果函数 foobar 足够短,编译器将复制 foobar 的整个代码而不是调用它,从而消除了 call 和 ret 指令的需要。这使代码更快了一点,但也使其更大。

考虑一个调用 100 次的 100 条指令函数。如果内联此函数,代码大小将急剧增加,而不会增加太多速度。如果您设置了高优化级别并且相关函数非常小,编译器只会内联代码。

您可能已经注意到,没有什么可以代替 foobar 函数。它已被“优化掉”,意味着编译器将其完全删除。这是因为编译器可以判断 foobar 没有做任何有用的事情。也就是说,它没有 side effects .在 -O0 处,没有任何优化。在更高的优化级别,gcc 开始优化没有副作用的函数以节省空间。

我已经有几年没有编写 x86 汇编了(现在只是 arm),但如果我没记错的话,由于分支预测,repz ret 实际上是一种更有效的 ret 形式。可以找到更多信息 here .

我得去 sleep 了。如果您还有问题,我会稍后回复:)。

关于c - 了解简单 C 程序的汇编,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30729736/

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