【汇编语言-6】 利用堆栈传递参数及堆栈的修正

 

一、调用子程序时信息的保护与恢复方法

(1) 在子程序中进行

SUBROUTE PROC
         
PUSH  AX
         
PUSH  BX
         
PUSH  CX
         ...
         
POP  CX
         
POP  BX
         
POP  AX
         
RET
SUBROUTE ENDP

 

(2) 在主程序中进行

         ...
         
PUSH  AX
         
PUSH  BX
         
PUSH  CX
         
CALL  SUBROUTE
         
POP  CX
         
POP  BX
         
POP  AX
         ...

 

 

二、利用堆栈传递参数及堆栈的修正

; 将一组BCD数转换成16位二进制数
;
主程序
STACK   SEGMENT STACK
        DB 
256  DUP(?)
STACK   ENDS

DATA    SEGMENT
BCD1    DB 07H,06H,07H,02H,03H
LENG1   DW 
5
RESULT  DW ?
DATA    ENDS

CODEM   SEGMENT
        ASSUME 
CS: CODEM,  DS: DATA,  SS: STACK
START:    MOV    AX,DATA
        
MOV    DS,AX
        
; 将被转换的BCD数所在单元段地址、偏移地址、BCD数的位数依次压栈,传递给子程序
         PUSH   DS
        
LEA    SI,BCD1
        
PUSH   SI
        
MOV    CX,LENG1
        
PUSH   CX
        ; 堆栈内容( 栈底: DS, SI, CX)
        
; 调用子程序
         CALL   FAR PTR BCD-16B
        
POP    DX
        
MOV    RESULT,DX
        
MOV    AH,4CH
        
INT    21H
CODEM  ENDS

CODES   SEGMENT
        ASSUME  
CS: CODES
BCD-16B PROC FAR
        ; 堆栈内容( 栈底:DS, SI, CX, CS, IP )// CS和IP是由于call far ptr标号指令的调用而自动压入的
        PUSH  BP    ;保存BP
        ; 堆栈内容(栈底:DS, SI, CX, CS, IP, BP)
                                             ↑sp当前指向
        MOV    BP,SP ;保存SP
        ; 堆栈内容(栈底:DS, SI, CX, CS, IP, BP)
                                             ↑_bp和sp的当前指向
         ; 子程序中的入栈操作
         PUSH   DS
        
PUSH   SI
        
PUSH   CX
        
PUSH   BX
        
PUSH   AX
        ; 堆栈内容(栈底:DS, SI, CX, CS, IP, BP, DS, SI, CX, BX, AX)
                                             ↑_bp指向           ↑_sp指向

        ; 根据BP取主程序传递过来的参数
         MOV    CX,[BP]+ 6
        MOV    SI,[BP]+ 8
        MOV    DS,[BP]+ 10
         ; 子程序的实际代码
         ADD    SI,CX
        
MOV    DX, 0
BCDL:     DEC    SI
        
PUSH   CX  
        
MOV    AL,[SI]
        
AND    AL,0FH
        
CBW
        
MOV    BX,AX
        
MOV    AX,DX
        
MOV    CX, 10
        
MUL    CX
        
MOV    DX,AX
        
ADD    DX,BX
        
POP    CX 
        LOOP  BCDL
        
; 计算结果入栈
         MOV    [BP]+ 10 ,DX
        
; 子程序中的出栈操作
         POP    AX
        
POP    BX
        
POP    CX
        
POP    SI
        
POP    DS
        ; 堆栈内容(栈底:DS, SI, CX, CS, IP, BP)
                                             ↑_bp和sp的当前指向

         ; 恢复BP
         POP    BP
        ; 堆栈内容(栈底:DS, SI, CX, CS, IP)
                                         ↑_sp的当前指向

         ; 该指令将返回地址弹出堆栈, 同时执行SP+4, 有效地将参数从堆栈中移除并返回到调用代码片
         RET     4
        ; 堆栈内容(栈底:DS, SI, CX)
                                 ↑_sp的当前指向

BCD-16B ENDP
CODES   ENDS
        END  START

 

 

三、利用堆栈传递参数的例子

ignore_int:
    pushl %eax
;信息保存
    pushl %ecx
    pushl %edx
    push  %ds
    
push  %es
    
push  %fs

    movl $0x10,%eax
     mov  %ax,%ds
    
mov  %ax,%es
    
mov  %ax,%fs
    pushl $int_msg
;prink函数的参数
    
call  _printk ; 
    popl %eax ;
在printk函数中,pop给eax的是堆栈中的什么值呢?怎么放到堆栈中去的? 程序自动处理的?

    
pop  %fs ;信息恢复
    
pop  %es
    
pop  %ds
    popl %edx
    popl %ecx
    popl %eax
    
iret

 

int  printk(const char *fmt, ...)
{
    va_list args
;
     int  i ;

    va_start(args, fmt)
;
    i=vsprintf(buf,fmt,args) ;
    va_end(args) ;
    __asm__( " push %%fs\n\t "     ; 保存fs
         " push %%ds\n\t "
        
" pop %%fs\n\t "
        ;在C语言中, 参数入栈顺序按被调用函数从右往左
        
" pushl %0\n\t "         ; 字符长度入栈
         " pushl $_buf\n\t "      ; buf入栈
         " pushl $0\n\t "         ; channel 0入栈
         " call _tty_write\n\t "
        
" addl $8,%%esp\n\t "    ;调用者修正堆栈(适用C)
         " popl %0\n\t "          ; 字符长度出栈
         " pop %%fs "             ; 恢复fs
        :: " r "  (i): " ax " , " cx " , " dx " ) ;
    return i ;
}

 

int  tty_write(unsigned channel, char * buf,  int  nr)
{
    ...
}

 

 

参考:Procedures and Functions

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值