x86 linux 反汇编问题

yu.sang 2016-11-30 09:40:06
测试c代码如下:(test.c)

struct data_st{
int a,b;
struct data_st *pnext;
};

int add_X(struct data_st data)
{
int a,b,c;
data.a = 10;
data.b = 5;
data.pnext = &data;
a = 1;
b = 2;
c = 3;
return 30001;
}

void call_X(void)
{
struct data_st data;
add_X(data);
}

int main()
{
int a = 0;
call_X();
return 0;
}


编译命令如下:
gcc -S -fno-asynchronous-unwind-tables test.c
汇编结果如下:


.file "test.c"
.text
.globl add_X
.type add_X, @function
add_X: #疑问三,这里咋没有sub ? 直接就那bp进行取数据了?
pushq %rbp
movq %rsp, %rbp
movq %rdi, %rax
movq %rsi, %rcx
movq %rcx, %rdx
movq %rax, -32(%rbp)
movq %rdx, -24(%rbp)
movl $10, -32(%rbp)
movl $5, -28(%rbp)
leaq -32(%rbp), %rax
movq %rax, -24(%rbp)
movl $1, -12(%rbp)
movl $2, -8(%rbp)
movl $3, -4(%rbp)
movl $30001, %eax
popq %rbp
ret
.size add_X, .-add_X
.globl call_X
.type call_X, @function
call_X:
pushq %rbp
movq %rsp, %rbp
subq $16, %rsp 疑问二,同疑问一,应该是12呀?
movq -16(%rbp), %rdx
movq -8(%rbp), %rax
movq %rdx, %rdi
movq %rax, %rsi
call add_X
leave
ret
.size call_X, .-call_X
.globl main
.type main, @function
main:
pushq %rbp
movq %rsp, %rbp
subq $16, %rsp #疑问1,这里为啥要减去16 ?而不是 4? a的size是4呀?
movl $0, -4(%rbp)
call call_X
movl $0, %eax
leave
ret
.size main, .-main
.ident "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4"



还请大神么,帮忙解答下汇编里注释的三个疑问。。非常感谢!!!!
...全文
148 14 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
ipqtjmqj 2016-11-30
  • 打赏
  • 举报
回复
我本来也不太懂汇编的,经过与楼主的讨论,加上自己的研究,下面是我的理解: 每个函数开头都会有这几句
pushq   %rbp
上面这句的目的是因为下面这句要使用bp,所以先保存一下
movq    %rsp, %rbp
上面这句是保存sp到bp中,由于push操作会改变sp, 所以保存sp只能用move语句 保存sp的目的是函数中的局部变量都保存在栈上,有新的变量定义sp的值就会改变, sp的原始值保存在bp中,这样函数结束时释放线变量只需令sp = bp即可。
subq    $16, %rsp
然而为了效率,并不是定义几个变量就对sp减几次,而是一次性分配一定空间。 改变sp的目的是为了让里层的函数以最新的sp为基址,所以最里层的函数就不需要改变sp了. 还有一点蛮奇怪的,函数开头有保存bp, sp函数结束时没有还原。 只有最里层函数用pop bp, 但貌似bp根本没变。 我猜测可能调用函数在父函数的最后一句,所以就不需要了
yu.sang 2016-11-30
  • 打赏
  • 举报
回复
引用 11 楼 ipqtjmqj 的回复:
[quote=引用 9 楼 shangyu0801 的回复:] [quote=引用 7 楼 ipqtjmqj 的回复:] 这毕竟是机器产生的,不完美,我仔细看了下,sp寄存器从头到尾都没啥用
sp是栈顶指针,所有的pop和push都是依赖这个的。 我就是看不懂这个逻辑,什么时候给add_x里的局部变量和形参分配的空间。。。咋上来就用bp指针取这些变量了~[/quote] 哦,这样就很好解释了,因为add_X函数里面有pop语句,所以sp不能变[/quote] 我觉得这个不是原因而是结果,因为bsp没有变化(sp == bp),所以才能用直接用pop bp,否则应该先执行sp = bp.然后在pop bp
yu.sang 2016-11-30
  • 打赏
  • 举报
回复
引用 5 楼 ipqtjmqj 的回复:
疑问三:因为是最里层的函数了
引用 10 楼 pengzhixi 的回复:
看了下 即使在add_X 里面return data也不会使用rsp分配空间。
good结合engzhixi的分析应该是这个原因了。因为是最底层,是不用修改esp的,因为不用记录当前的堆栈使用情况,返回该函数退出时直接拿到ebp就OK。 我在add_X里再调用一个函数,就发现有sub xx,%rsp的操作了。 值得一提的是,在vs下,一直都是有sub xx,%rsp的操作的。。
ipqtjmqj 2016-11-30
  • 打赏
  • 举报
回复
引用 9 楼 shangyu0801 的回复:
[quote=引用 7 楼 ipqtjmqj 的回复:] 这毕竟是机器产生的,不完美,我仔细看了下,sp寄存器从头到尾都没啥用
sp是栈顶指针,所有的pop和push都是依赖这个的。 我就是看不懂这个逻辑,什么时候给add_x里的局部变量和形参分配的空间。。。咋上来就用bp指针取这些变量了~[/quote] 哦,这样就很好解释了,因为add_X函数里面有pop语句,所以sp不能变
pengzhixi 2016-11-30
  • 打赏
  • 举报
回复
看了下 即使在add_X 里面return data也不会使用rsp分配空间。
yu.sang 2016-11-30
  • 打赏
  • 举报
回复
引用 7 楼 ipqtjmqj 的回复:
这毕竟是机器产生的,不完美,我仔细看了下,sp寄存器从头到尾都没啥用
sp是栈顶指针,所有的pop和push都是依赖这个的。 我就是看不懂这个逻辑,什么时候给add_x里的局部变量和形参分配的空间。。。咋上来就用bp指针取这些变量了~
pengzhixi 2016-11-30
  • 打赏
  • 举报
回复
引用 6 楼 shangyu0801 的回复:
[quote=引用 3 楼 shangyu0801 的回复:] 而且,如果是调用前分配的,那么在call_x里通过bp调用时,肯定是正偏移,而不应该是负的偏移呀。
说错了,我的意思是在add_x里,取值的时候,应该是 movq %rax, 32(%rbp) movq %rdx, -24(%rbp)
引用 5 楼 ipqtjmqj 的回复:
疑问三:因为是最里层的函数了
没理解呀!与非里层的函数有什么区别么?[/quote]经楼主提醒 又去看了下,觉得应该是编译器做的优化。没有对rsp做修改,而是直接用rbp来为add_X(struct data_st data)这个参数分配空间,能想到的一个好处就是不用对rsp做进一步的恢复。因为你传递的不是指针,函数调用返回 这个参数所在的空间就不可用。所以优化一下不用rsp分配空间,直接用rhp 减去某个值来使用栈。 返回的时候又不用恢复rsp。还挺好
ipqtjmqj 2016-11-30
  • 打赏
  • 举报
回复
这毕竟是机器产生的,不完美,我仔细看了下,sp寄存器从头到尾都没啥用
yu.sang 2016-11-30
  • 打赏
  • 举报
回复
引用 3 楼 shangyu0801 的回复:
而且,如果是调用前分配的,那么在call_x里通过bp调用时,肯定是正偏移,而不应该是负的偏移呀。
说错了,我的意思是在add_x里,取值的时候,应该是 movq %rax, 32(%rbp) movq %rdx, -24(%rbp)
引用 5 楼 ipqtjmqj 的回复:
疑问三:因为是最里层的函数了
没理解呀!与非里层的函数有什么区别么?
ipqtjmqj 2016-11-30
  • 打赏
  • 举报
回复
疑问三:因为是最里层的函数了
赵4老师 2016-11-30
  • 打赏
  • 举报
回复
没准默认被优化了。 http://edu.csdn.net/course/detail/2344 C语言指针与汇编内存地址-一.代码要素
yu.sang 2016-11-30
  • 打赏
  • 举报
回复
而且,如果是调用前分配的,那么在call_x里通过bp调用时,肯定是正偏移,而不应该是负的偏移呀。
yu.sang 2016-11-30
  • 打赏
  • 举报
回复
引用 1 楼 pengzhixi 的回复:
subq $16, %rsp #疑问1,这里为啥要减去16 ?而不是 4? a的size是4呀? 这个再debug模式下不一定是4,但是这个 不重要 你只需要看movl $0, -4(%rbp)这个对a进行赋值的时候没有取错就好了。我个人猜测只是出于对齐的考虑。这个和疑问二可以算是同一个问题。 #疑问三,这里咋没有sub ? 直接就那bp进行取数据了? 这个参数的空间是调用的时候有调用函数分配了。具体你可以调用下add_x就知道了
感谢!! add_x已经在call_x里被调用了。call_x里并没有分配的地方啊?
pengzhixi 2016-11-30
  • 打赏
  • 举报
回复
subq $16, %rsp #疑问1,这里为啥要减去16 ?而不是 4? a的size是4呀? 这个再debug模式下不一定是4,但是这个 不重要 你只需要看movl $0, -4(%rbp)这个对a进行赋值的时候没有取错就好了。我个人猜测只是出于对齐的考虑。这个和疑问二可以算是同一个问题。 #疑问三,这里咋没有sub ? 直接就那bp进行取数据了? 这个参数的空间是调用的时候有调用函数分配了。具体你可以调用下add_x就知道了

70,020

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧