源文件如下,命名为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