为什么printf的参数是从右向左压栈

源文件如下,命名为casimodo.c:
main()
{
int i=5,k;
k=(++i)+(++i)+(i++);
printf("%d/n",i);
i=5;
printf("%d,%d,%d,%d",i,k,(++i)+(++i)+(i++),i);
}

用tcc -B反编译casimodo.c:

 ifndef ??version
?debug macro
 endm
 endif
 ?debug S "casimdo1.c"

_TEXT segment byte public 'CODE'
DGROUP group _DATA,_BSS
 assume cs:_TEXT,ds:DGROUP,ss:DGROUP
_TEXT ends

_DATA segment word public 'DATA'
d@  label  byte
d@w  label  word
_DATA ends

_BSS segment word public 'BSS'
b@ label byte
b@w label word
 ?debug C E98A752C320A636173696D646F312E63
_BSS ends

_TEXT segment byte public 'CODE'
; ?debug L 1
_main proc near
 push si
 push di
; ?debug L 4
 mov si,5
; ?debug L 5
 inc si    ;第一次++i  i=6
 inc si    ;第二次++i  i=7
 mov di,si   ;执行k=++i
 add di,si   ;执行k=(++i)+(++i)
 add di,si   ;执行k=(++i)+(++i)+(i++) 此时i=7
 inc si     ;就是那个i++  i=8
; ?debug L 6
 push si    ;si入栈,保存i的值 准备printf
 mov ax,offset DGROUP:s@ ;得到printf函数的打印格式参数
 push ax         ;参数入栈
 call near ptr _printf     
 pop cx         ;还原堆栈指针         
 pop cx
; ?debug L 7
 mov si,5
; ?debug L 8
 push si         ;si入栈,i=5,保存i的值        
 inc si          ;++i   i=6
 mov ax,si        ;ax=6,
 inc si          ; ++i  i=7
 mov dx,si        ;dx=7 
 add ax,dx        ;计算(++i)+(++i),存在ax中ax=13
 mov dx,si        ;dx=7
 inc si          ;++i  i=8
 add ax,dx        ;计算(++i)+(++i)+(i++),ax= 21
 push ax         ;ax又入栈 
 push di         ;di,si入栈 ,就是k,i 值入栈
 push si
 mov ax,offset DGROUP:s@+4   ;在printf的打印参数数据中取第二次的参数
 push ax            ;ax入栈
 call near ptr _printf        ;打印
 add sp,10
@1:
; ?debug L 9
 pop di
 pop si
 ret 
_main endp
_TEXT ends

 ?debug C E9
_DATA segment word public 'DATA'
s@ label byte
 db 37     ;是第一次打印参数 37实际就是%
 db 100    ;d 
 db 10     ;换行符\n
 db 0      
 db 37     ;第二次打印参数
 db 100     
 db 44     ;","
 db 37
 db 100
 db 44
 db 37
 db 100
 db 44
 db 37
 db 100
 db 0
_DATA ends

_TEXT segment byte public 'CODE'
 extrn _printf:near
_TEXT ends

 public _main
 end

看来,还要在 call _printf这里面找,先放放,去找w32dasm



找到 w32dasm. 白菜乐园 ,
两个call  _printf调用的是同一个地址的函数,在
* Referenced by a CALL at Addresses:
|:0001.0210, :0001.022D
|
:0001.0AEB 55                     push bp                       ;bp中存放着返回地址
:0001.0AEC 8BEC                   mov bp, sp    
:0001.0AEE B8630C                 mov ax, 0C63  ;
:0001.0AF1 50                     push ax
:0001.0AF2 B81C02                 mov ax,021C
:0001.0AF5 50                     push ax
:0001.0AF6 FF7604                 push word ptr [bp+04]
:0001.0AF9 8D4606                 lea ax, [bp+06]   ;ax=ffdc,而ffdc就是 i值8
:0001.0AFC 50                     push ax       
:0001.0AFD E84C02                 call 0D4C
:0001.0B00 EB00                   jmp 0B02
 
用debug:
-g  0aeb

AX=0194  BX=07DC  CX=0010  DX=E595  SP=FFD8  BP=FFE2  SI=0008  DI=0015
DS=14F2  ES=14F2  SS=14F2  CS=13B9  IP=0AEB   NV UP EI PL NZ NA PO NC
13B9:0AEB 55            PUSH    BP
-t

AX=0194  BX=07DC  CX=0010  DX=E595  SP=FFD6  BP=FFE2  SI=0008  DI=0015
DS=14F2  ES=14F2  SS=14F2  CS=13B9  IP=0AEC   NV UP EI PL NZ NA PO NC
13B9:0AEC 8BEC          MOV     BP,SP
-d ds:ffd6
14F2:FFD0                    E2 FF-13 02 94 01 08 00 9B 07         ..........
14F2:FFE0  20 03 EE FF 1D 01 01 00-EC FF A4 07 F0 FF 00 00    ...............
14F2:FFF0  43 41 53 49 4D 4F 44 4F-2E 45 58 45 00 00 FB 00   CASIMODO.EXE....

查看堆栈知道那个ffe2就是被保存的bp的值,
0213 这个值就是printf返回的地址
0194 就是打印格式参数地址
那个 8,就是 i 的值了

又有个call,跟进:

* Referenced by a CALL at Address:
|:0001.0AFD
|
:0001.0D4C 55                     push bp    ;bp=ffd6
:0001.0D4D 8BEC                   mov bp, sp  ;sp=ffca
:0001.0D4F 81EC9600               sub sp, 0096  ;不懂 sp=ff34
:0001.0D53 56                     push si      ;si=8
:0001.0D54 57                     push di      ;di=15
:0001.0D55 C746AA0000             mov word ptr [bp-56], 0000
:0001.0D5A C646AD50               mov byte ptr [bp-53], 50
:0001.0D5E EB38                   jmp 0D98    ;无条件转到0D98

继续来,好痛苦
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0001.0D5E(U)
|
:0001.0D98 06                     push es
:0001.0D99 FC                     cld      ;
清方向标志位
:0001.0D9A 8D7EAE                 lea di, [bp-52] ;di=ff78
:0001.0D9D 89BE6CFF               mov [bp+FF6C], di ;

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0001.1221(U)
|
:0001.0DA1 8BBE6CFF               mov di, [bp+FF6C]

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:0001.0FB9(U), :0001.11F4(U)
|
:0001.0DA5 8B7606                 mov si, [bp+06]  ;si=0194

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:0001.0DB7(C), :0001.0DBC(U)
|
:0001.0DA8 AC                     lodsb   ;
把源串中的字符逐一装入AL或ax中,ax=ff25
:0001.0DA9 0AC0                   or al , al  ;ss:ff25=ffca ss:ffca=ffd6  s:ffd6就是我们的原始数据
:0001.0DAB 7411                   je 0DBE  ;因为z=0,不跳转
:0001.0DAD 3C25                   cmp al, 25  ;z=1
:0001.0DAF 7410                   je 0DC1   


参考文章:
http://www.csdn.com.cn/program/6717.htm
http://www.cstc.net.cn/docs/docs.php?id=275


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值