目录
案例分析
案例一代码
bubbleSort proc
;bubbleSort(int *arr,int len) call C style
;input:
;push len
;push offset arr
push ebp
mov ebp,esp
pushad
mov edx,[ebp+8]
mov ecx,[ebp+12]
mov esi,0;i=esi
sub ecx,1;ecx=n-1
again_1: cmp esi,ecx
jge final_1
mov edi,0;j=edi
mov ebx,ecx
sub ebx,esi
again_2: cmp edi,ebx;ebx=n-1-i
jge final_2
mov eax,[edx+4*edi]
cmp eax,[edx+4*edi+4]
jle next
push [edx+4*edi+4]
pop [edx+4*edi]
mov [edx+4*edi+4],eax
next: inc edi
jmp again_2
final_2:
inc esi
jmp again_1
final_1:
popad
pop ebp
ret 8
bubbleSort endp
output proc
;output(int *arr ,int len)
;input:
;edx=arr
;ecx=len
pushad
mov esi,0
again: cmp esi,ecx
jge final
mov eax,[edx+4*esi]
call writeint
mov al,' '
call writechar
inc esi
jmp again
final: popad
ret
output endp
分析
push len
push offset arr先将长度和首地址进行入栈
push ebp
mov ebp,esp
pushad将ebp进栈方便对len和arr进行寻址,将各寄存器进栈
mov edx,[ebp+8]
mov ecx,[ebp+12]此时edx,ecx分别为arr首地址和长度
进行逻辑运算后
popad
pop ebpret 8
将各寄存器出栈,将ebp出栈,ret 8让栈平衡
案例二代码
- 源代码
void insertionSort( int arr[], int n){
int i;
for(i = 1; i < n; i++) {
insert(arr, i);
}
}
void insert ( int arr[], int n){
int key = arr[n];
int i = n;
while (arr[i - 1] > key) {
arr[i] = arr[i-1];
i--;
if(i == 0) break;
}
arr[i] = key;
}
- 汇编代码
INCLUDE Irvine32.inc
.data
arr dd 99, 2, 3, -11, 22, 88, 7, 77, 547, 717, -54
len dd ($-arr)/4
a dd ?
.code
insert PROC
;arr,a(i)
push ebp
mov ebp,esp
pushad
mov ebx,[ebp+8];ebx=i(n)
mov eax,[ebp+12];eax=arr
mov ecx,[eax+ebx*4];ecx=key
again:
cmp [eax+4*ebx-4],ecx
jle final
mov edx,[eax+4*ebx-4]
mov [eax+4*ebx],edx
sub ebx,1
cmp ebx,0
je final
jmp again
final:
mov [eax+4*ebx],ecx
popad
pop ebp
ret 8
insert ENDP
main PROC
mov a,1
again:
mov eax,a;a为下标(eax)
cmp eax,len;(len=n)
jae myout
push offset arr
push a
call insert
add a,1
jmp again
myout:
mov ebx,0
again2:
cmp ebx,len
jae final2
mov eax,arr[ebx*4]
call WriteInt
add ebx,1
jmp again2
final2:
exit
main ENDP
END main
案例三代码
include irvine32.inc
.dataarr dd 99, 2, 3, 1, 22, 88, 7, 77, 54
len dd ($-arr)/4
.code
slectSort proc
;;;;;void slectSort(int *arr,int n)
;;;;input:
;;;;;;;;;push n
;;;;;;;;;push offset arr
push ebp
mov ebp,esp
pushad
mov edx,[ebp+8];;edx:arr
mov esi,[ebp+12];;;;esi:i;i=n
again: cmp esi,1
jle final
push esi
push edx
call maxIndex;;;eax:j= maxIndex(arr,esi);
mov ebx,[edx+4*eax]
mov ecx,[edx+4*esi-4]
mov [edx+4*eax],ecx
mov [edx+4*esi-4],ebx
dec esi
jmp again
final: popad
pop ebp
ret 8
slectSort endpmaxIndex proc
;;;;maxIndex(int*arr,int n)
;;;;input:
;;;;;;;;;push n
;;;;;;;;;push offset arr
;;;;;;;;;return:eax
push ebp
mov ebp,esp
sub esp,4
pushad
mov edx,[ebp+8]
mov eax,0;;;eax:index
mov esi,0;;;esi:i
again: cmp esi,[ebp+12]
jge final
mov ebx,[edx+4*eax]
cmp ebx,[edx+4*esi]
jge next
mov eax,esi
next: inc esi
jmp again
final: mov [ebp-4],eax
popad
mov eax,[ebp-4]
add esp,4
pop ebp
ret 8
maxIndex endp
output proc
push esi
push ecx
push eax
mov esi,0
again: cmp esi,ecx
jge final
mov eax,[edx+4*esi]
call writeint
mov al,' '
call writechar
add esi,1
jmp again
final: pop eax
pop ecx
pop esi
ret
output endp
main proc
push len
push offset arr
call slectSort
mov edx,offset arr
mov ecx,len
call output
exit
main endpend main
main() {
int arr[] = {99, 2, 3, 1, 22, 88, 7, 77, 54};
int i;
slectSort(arr, 9);
for (int i = 0; i < 9; i++)
cout << arr[i] << endl;
return 0;
}
分析
这里主要分析以下部分代码
sub esp,4
final:
mov [ebp-4],eax
popad
mov eax,[ebp-4]
add esp,4
pop ebp
ret 8
由于要将运算的结果通过寄存器eax返回父函数,而eax在final的popad中被出栈导致数据丢失。此时我们在ebp进栈后通过sub esp,4开辟一个空间,运算结束后先将eax的值赋值给ebp-4这个空间,然后将popad,然后取出空间的值重新赋值给eax,然后将esp+4覆盖掉开辟的空间,最后弹出ebp,ret 8即可。
知识补充
- 栈传参的好处
子函数的运算不影响父函数寄存器存储的值,在递归中避免出现赋值的覆盖。还能避免传参的个数超出寄存器的数量。
当我们在执行函数调用时,寄存器不够用的时候,我们可以使用堆栈传参,比如说,我们要计算任意10个参数相加的和,如果按照之前文章的办法,我们会使用mov这个指令把参数传递到寄存器中进行计算,但是通用寄存器只有八个,我们现在要传递十个参数,这时候就可以使用栈传参了。
- 寄存器批量进(出)栈
- 数据交换
- 换行函数
call crlf
- 输出空格
mov al,' '
call writechar