【汇编】用栈传参的案例及分析

目录

案例分析

案例一代码

分析

案例二代码

案例三代码

分析

知识补充


案例分析

案例一代码

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 ebp

ret 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
.data

arr 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 endp

maxIndex 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 endp

end 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

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

coleak

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值