#include<iostream> | #include<iostream> |
using namespace std; | using namespace std; |
void swap(int i,int j) | void myswap(int &i,int &j) |
{ | { |
int a=i; | int a=i; |
i=j; | i=j; |
j=a; | j=a; |
} | } |
int main() | int main() |
{ | { |
int i=0,j=1; | int i=0,j=1; |
swap(i,j); | myswap(i,j); |
cout<<i<<" "<<j; | cout<<i<<" "<<j; |
system("pause"); | system("pause"); |
return 0; | return 0; |
} | } |
var_8= dword ptr -8 | var_8= dword ptr -8 | |
var_4= dword ptr -4 | var_4= dword ptr -4 | |
argc= dword ptr 8 | argc= dword ptr 8 | |
argv= dword ptr 0Ch | argv= dword ptr 0Ch | |
envp= dword ptr 10h | envp= dword ptr 10h | |
push ebp | push ebp | |
mov ebp, esp | mov ebp, esp | |
sub esp, 8 | sub esp, 8 | |
mov [ebp+var_4], 0 | mov [ebp+var_4], 0 | |
mov [ebp+var_8], 1 | mov [ebp+var_8], 1 | |
mov eax, [ebp+var_8] | lea eax, [ebp+var_8] | |
push eax | push eax | |
mov ecx, [ebp+var_4] | lea ecx, [ebp+var_4] | |
push ecx | push ecx | |
call sub_401000 | call sub_401000 | |
add esp, 8 | add esp, 8 | |
mov edx, [ebp+var_8] | mov edx, [ebp+var_8] | 前面都是一样的 |
push edx | push edx | |
push offset asc_41C1D8 ; " " | push offset asc_41C1D8 ; " " | |
mov eax, [ebp+var_4] | mov eax, [ebp+var_4] | |
push eax | push eax | |
mov ecx, offset unk_422858 | mov ecx, offset unk_422858 | |
call sub_401080 | call sub_401090 | |
push eax ; int | push eax ; int | |
call sub_402410 | call sub_402420 | |
add esp, 8 | add esp, 8 | |
mov ecx, eax | mov ecx, eax | |
call sub_401080 | call sub_401090 | |
push offset aPause ; "pause" | push offset aPause ; "pause" | |
call unknown_libname_33 ; Microsoft VisualC 2-8/net runtime | call unknown_libname_33 ; Microsoft VisualC 2-8/net runtime | |
add esp, 4 | add esp, 4 | |
xor eax, eax | xor eax, eax | |
mov esp, ebp | mov esp, ebp | |
pop ebp | pop ebp | |
retn | retn | |
sub_401000 proc near | sub_401000 proc near | |
var_4= dword ptr -4 | var_4= dword ptr -4 | |
arg_0= dword ptr 8 | arg_0= dword ptr 8 | |
arg_4= dword ptr 0Ch | arg_4= dword ptr 0Ch | |
push ebp | push ebp | |
mov ebp, esp | mov ebp, esp | |
push ecx | push ecx | |
mov eax, [ebp+arg_0] | mov eax, [ebp+arg_0] | 这儿就是值传递和引用传递的区别 |
mov [ebp+var_4], eax | mov ecx, [eax] | |
mov [ebp+var_4], ecx | ||
mov ecx, [ebp+arg_4] | mov edx, [ebp+arg_0] | |
mov [ebp+arg_0], ecx | mov eax, [ebp+arg_4] | |
mov ecx, [eax] | ||
mov [edx], ecx | ||
mov edx, [ebp+var_4] | mov edx, [ebp+arg_4] | |
mov [ebp+arg_4], edx | mov eax, [ebp+var_4] | |
mov [edx], eax | ||
mov esp, ebp | mov esp, ebp | |
pop ebp | pop ebp | |
retn | retn | |
sub_401000 endp | sub_401000 endp |
#include<iostream> | #include<iostream> |
using namespace std; | using namespace std; |
int add(int i) | inline int add(int i) |
{ | { |
return (i+1); | return (i+1); |
} | } |
int main() | int main() |
{ | { |
int i=0; | int i=0; |
i=add(i); | i=add(i); |
cout<<i; | cout<<i; |
system("pause"); | system("pause"); |
return 0; | return 0; |
} | } |
var_4= dword ptr -4 | var_4= dword ptr -4 | |
argc= dword ptr 8 | argc= dword ptr 8 | |
argv= dword ptr 0Ch | argv= dword ptr 0Ch | |
envp= dword ptr 10h | envp= dword ptr 10h | 最奇怪的应该是这儿,就是在调用内联函数时没有发生插入,而只是直接调用。我猜可能是出于使用这个函数的次数太少的原因,以致插入的代价要远远大于调用的代价。我就设计了另外一个程序,其中有双层for循环调用了10000*10000次内联函数,很奇怪的是仍然是直接调用而不是插入。我只能猜测在for循环连续调用一个函数时,系统作了优化,使得插入的效率没有直接调用高。于是我就只能猜测在每次调用内联函数程序处于不同的环境下,才直接插入,否则就直接调用。 |
push ebp | push ebp | |
mov ebp, esp | mov ebp, esp | |
push ecx | push ecx | |
mov [ebp+var_4], 0 | mov [ebp+var_4], 0 | |
mov eax, [ebp+var_4] | mov eax, [ebp+var_4] | |
push eax | push eax | |
call sub_401000 | call sub_401040 | |
add esp, 4 | add esp, 4 | |
mov [ebp+var_4], eax | mov [ebp+var_4], eax | |
mov ecx, [ebp+var_4] | mov ecx, [ebp+var_4] | |
push ecx | push ecx | |
mov ecx, offset unk_422858 | mov ecx, offset unk_422858 | |
call sub_401050 | call sub_401050 | |
push offset aPause ; "pause" | push offset aPause ; "pause" | |
call unknown_libname_33 ; Microsoft VisualC 2-8/net runtime | call unknown_libname_33 ; Microsoft VisualC 2-8/net runtime | |
add esp, 4 | add esp, 4 | |
xor eax, eax | xor eax, eax | |
mov esp, ebp | mov esp, ebp | |
pop ebp | pop ebp | |
retn | retn | |
sub_401000 proc near | sub_401040 proc near | |
arg_0= dword ptr 8 | arg_0= dword ptr 8 | |
push ebp | push ebp | |
mov ebp, esp | mov ebp, esp | |
mov eax, [ebp+arg_0] | mov eax, [ebp+arg_0] | |
add eax, 1 | add eax, 1 | |
pop ebp | pop ebp | |
retn | retn | |
sub_401000 endp | sub_401040 endp |
反思: | 内联函数这块海需要好好考证。 |
下步: | 作文件的读取等操作。 |
在网上搜索到一篇call和ret有关的文章,转来看看
1)段内直接调用
指令格式: CALL 过程名
功 能: SP←SP-2,[SP+1][SP]←IP,IP←IP+displ6
操作说明: 被调用过程是一个近过程,在本代码段内。CALL指令将IP(返回地址)压入堆栈,然后将CALL的下一条指令与被调用过程入口地址之间的16位相对位移量displ6加到IP上,使控制转到被调用的过程。
2)段内间接调用
指令格式: CALL 字地址指针
功 能: SP←SP-2,[SP+1][SP] ←IP,IP←EA
操作说明: 指令中的操作数是一个16位的寄存器或字存储单元,其中的内容是一个近过程的入口地址。CALL指令将返回地址IP压入堆栈,然后将寄存器或字存储单元的内容作为有效地址装入IP。
3)段间直接调用
指令格式: CALL FAR PTR过程名
功 能: SP←SP-2,[SP+1][SP] ←CS,CS←SEG FAR-PROC
SP←SP-2,[SP+1][IP] ←IP,IP←OFFSET FAR-PROC
操作说明: 被调用过程是一个远过程,该过程不在现行代码段内。段间直接调用指令首先将CS(断点的段基址)压入堆栈,并将远过程所在的段基址SEG FAR—PROC送CS;再将IP(断点的偏移地址)压入堆栈,然后将远过程的偏移地址OFFSETFAR-PROC送IP。
4)段间间接调用
指令格式: CALL 双字地址指针
功 能: SP←SP-2,[SP+1][SP] ←CS,CS←[EA+2]
SP←SP-2,[SP+1][SP] ←IP,IP←[EA]
操作说明: 指令操作数是一个32位的双字存储单元,指令将CS寄存器的内容压入堆栈,并将操作数指向的存储器的后两个字节送CS;再将IP寄存器的内容压入堆栈,然后将存储器的前两个字节送IP。
【例2.53】 CALL SUB-PROCA ;段内直接调用
CALL AX ;段内间接调用
CALL WORD PTR[BX] ;段内间接调用
CALL FAR PTR SUB-PROCX ;段间直接调用
CALL DWORD PTR[BP][SI] ;段间间接调用
(2)过程返回指令
子过程执行最后一条指令必须是返回指令,返回到调用该子程序断点处。
1)返回指令
指令格式: RET
功 能: 从近过程返回时:IP←[SP+1][SP],SP←SP+2
从远过程返回时:IP←[SP+1][SP],SP←SP+2
CS←[SP+1][SP],SP←SP+2
2)带弹出值的返回指令
指令格式: RET POP_VALUE
功 能: 先执行与RET相同的操作,再修改SP: SP←SP+POP_VALUE。
操作说明: 弹出值应为一个16位立即数,通常是偶数。弹出值表示返回时从堆栈中舍弃的字节数。例如:RET 4,返回时舍弃堆栈中的4个字节。