问一小段c语言编译出来的汇编,本人的汇编水平很次,请详细解答,谢谢!

leonatcs 2006-12-18 12:44:29
代码如下:
_TEXT segment dword public use32 'CODE'
_fun proc near
?live1@0:
;
; int fun(int *a) {return ++(*a);}
;
push ebp
mov ebp,esp
@1:
mov eax,dword ptr [ebp+8]
inc dword ptr [eax]
mov eax,dword ptr [eax]
@3:
@2:
pop ebp
ret
_fun endp
_TEXT ends


_TEXT segment dword public use32 'CODE'
_main proc near
?live1@48:
;
; int main(int argc, char* argv[])
;
push ebp
mov ebp,esp
push ebx
;
; {
; static x = 47;
; int a = 3;
;
@4:
mov eax,3
;
; int b = (a*10) + (a=a+1);
;
?live1@80: ; EAX = a
inc eax
;
; int y = (10*(fun(&x)-46)) + (fun(&x)-46);
;
?live1@96: ;
push offset $aoidcaia
call _fun
pop ecx
mov ebx,eax
push offset $aoidcaia
call _fun
pop ecx
add eax,-46
add eax,eax
lea eax,dword ptr [eax+4*eax]
add ebx,eax
mov eax,ebx
add eax,-46
;
; printf("%d",y);
;
?live1@112: ; EAX = y
push eax
push offset s@
call _printf
add esp,8
;
; system("pause");
;
?live1@128: ;
push offset s@+3
call _system
pop ecx
;
; return 0;
;
xor eax,eax
;
; }
;
@6:
@5:
pop ebx
pop ebp
ret
_main endp
_TEXT ends

问题:
1.“?live1@48:”这个是什么意思?如果是行标记,为什么起这样的名字?
2.“call _fun”之后为什么要“pop ecx”?
3.我猜测 add eax,eax
lea eax,dword ptr [eax+4*eax]
是给eax乘10,但是具体是怎么实现的呢?
4.add ebx,eax
mov eax,ebx
为什么不直接写 add eax,ebx 呢?
...全文
365 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
LiChenYue 2006-12-19
  • 打赏
  • 举报
回复
楼上正解,学习一下!
CharlesPrince 2006-12-19
  • 打赏
  • 举报
回复
1.“?live1@48:”这个是什么意思?如果是行标记,为什么起这样的名字?
答:?live1@48:是行号的标志,@后的数字表示行号,使用?live1@这是编写者自定的关键字。

2.“call _fun”之后为什么要“pop ecx”?
答:因为ECX参与了fun函数的运算,在fun函数中 push ecx,当fun执行完成后,当然要pop ecx.

3.我猜测 add eax,eax
lea eax,dword ptr [eax+4*eax]
是给eax乘10,但是具体是怎么实现的呢?
答:1.add eax,eax 相当于是eax * 2,但使用加法速度更快
2.lea eax,dword ptr [eax+4*eax] 相当于eax * 5,但相对于乘法速度更快

4.add ebx,eax
mov eax,ebx
为什么不直接写 add eax,ebx 呢?
答:因为还需要给ebx赋值

leonatcs 2006-12-19
  • 打赏
  • 举报
回复
谢谢rulary(秦枫)!搞清楚第三个了。今天在网上还搜到lea只能乘2、4、8。

谢谢楼上,关于第四问,为什么还要给ebx赋值呢?


leonatcs 2006-12-18
  • 打赏
  • 举报
回复
谢谢楼上!
这个是用bcc32从c语言编译出的汇编。
为什么不直接给eax乘10呢?lea不是load effective address吗?
rularys 2006-12-18
  • 打赏
  • 举报
回复
lea 指令的作用是取得源操作数的有效地址,


“lea eax,dword ptr [eax+4*eax]”在这里用的很巧妙,“[eax+4*eax]”表达式本身就是完成对eax乘以5的运算,该表达式可以在lea指令中附带完成,这时候eax中就是结果了,比如是12345678h,那么该条指令最终完成的任务就是将eax所指向的内存的地址取得并放入eax之中,也就是将地址为12345678h的内存的地址放到eax之中,呵呵,那么12345678h也就是运算结果就被放入eax之中了

该指令的妙处是能在一个指令周期之内完成源操作数(即“dword ptr [eax+4*eax])的运算,这样速度当然快了
leonatcs 2006-12-18
  • 打赏
  • 举报
回复
谢谢大家!
就剩下第四问了!
还有,我对
lea eax,dword ptr [eax+4*eax]
还是不太理解,lea本来是干什么用的?为什么可以实现乘5的效果呢?
rularys 2006-12-18
  • 打赏
  • 举报
回复
这个和“call _printf”后面的“add esp,8”指令是一样的道理,因为该call 指令之前有两个push 指令(总共压入了两个双字即8个字节),所以要将堆栈指针减掉相应的字节数以恢复到之前的堆栈
rularys 2006-12-18
  • 打赏
  • 举报
回复
Re :
<2.“call _fun”之后为什么要“pop ecx”?>
____________________________________________

pop ecx 指令应该是为了平衡堆栈用的,因为在call指令之前有一个push 指令。我估计,所调用的函数应该是c调用规则,该规则规定函数参数的堆栈平衡由调用者来完成。
大熊猫侯佩 2006-12-18
  • 打赏
  • 举报
回复
楼主这是从哪里看到的代码?这好像类似hla生成的asm代码,“?live1@48:”
很像是编译器自动生成的标号名

add eax,eax
lea eax,dword ptr [eax+4*eax]

(eax*2)+(4*2*eax) = 2eax + 8eax = 10eax
大熊猫侯佩 2006-12-18
  • 打赏
  • 举报
回复
乘指令要占用上百个时钟周期,所以不到没有办法一般都不会轻易使用mul指令
xkw365 2006-12-18
  • 打赏
  • 举报
回复
这应该是代码优化效率问题,直接乘10所用的时间要长,把乘10分解成(2+4*2)要好

21,458

社区成员

发帖
与我相关
我的任务
社区描述
汇编语言(Assembly Language)是任何一种用于电子计算机、微处理器、微控制器或其他可编程器件的低级语言,亦称为符号语言。
社区管理员
  • 汇编语言
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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