汇编中的函数调用:call

来源:互联网 发布:文明6 mac 迅雷下载 编辑:程序博客网 时间:2024/05/18 22:16

(说明:1、采用nasm语法,';'冒号表示后面的为注释

       2、程序是在实模式下运行的,所以所有寄存器都是16位的,地址也是16位表示的

       3、程序的功能是调用一个函数将一个字符串打印出来,字符串长度参数保存在栈中

       4、将每条语句、数据在内存中的地址以及有些寄存器中的值显示出来

       5、可以使用nasm编译生成com文件,在DOS虚拟机中使用Turbo Debugger(tasm内嵌工具)调试)

org 0x100
jmp code                        ;cs:0100: jmp 0x0118    ;E91500

[section .data]             ;cs:0103;               ;00为何空1个字节,难道是为了对齐?
param1 dw 0x000D                ;ds:0104:               ;0D 00数据从低地址到高地址排列
param2 dd 0x00000001            ;ds:0106:               ;01 00 00 00
strHello db "Hello, world!",0Ah ;ds:010A~011F:          ;48 65 6C 6C ...0A
STRLEN  equ $ - strHello

[section .code]
code:
 mov ax, cs                      ;cs:0118;               ;8CC8
 mov ds, ax                      ;cs:011A;               ;8ED8
 mov es, ax                      ;cs:011C;               ;8EC0
 mov ss, ax                      ;cs:011E;               ;8ED0
 mov sp, 0x100 ;0~0x100可作为堆栈空间;cs:0120            ;BC0001
 
 ;mov ax, STRLEN
 ;mov word [param1], ax          ;其实应该要这么写
 
 push word [param1]                     ;cs:0123; push word ptr [0104]   ;FF360401
 push dword [param2]                    ;cs:0127; push dword ptr [0106]  ;66FF360601
 ;0x0104,0x0106即为param2,param1的地址,这里知道push的是变量的值
 ;如果是push param1/param2的话则是param1/param2的地址,因为是在16位(dos)下,地址值占两个字节.
 ;此时堆栈0x0100前6个字节的值ds:00FA:   01 00 00 00 0D 00
 ;sp的值为00FA
 call called                    ;cs:012C; call  0134    ;E80500
                 ;要调试的话,需要在called中设断点,或者F7Trace,就相当于C语言中一样
                                  ;实际上这还是段内跳转,cs没有变,如何实现段间跳转呢?
 jmp $                           ;cs:012F; jmp 012F      ;EBFE
 
[section .called]                 ;cs:0131;          ;000000;为何留三个字节,难道又是为了对齐?
called:
 push bp                       ;cs:0134;               ;55
 mov  bp, sp ;防止修改堆栈把调用函数的数据覆盖;cs:0135  ;89E5
 mov  ax, strHello              ;cs:0137; mov ax, 010A  ;B80A01
                                         ;010A为strHello的地址
 mov  bp, ax                    ;cs:013A;               ;89C5
 mov  dl, 0                     ;cs:013C;               ;B200
 mov  cx, [esp+8]               ;cs:013E;               ;678B442408
 ;涉及到取地址时,不能是两个字节的寄存器如sp,只能是esp!
 ;这时的堆栈如下所示
 ;high address(00FF)    00
 ;            (00FE)    0D  (0x000D表示param1的值,地址为0x0104)
 ;            (00FD)    00
 ;            (00FC)    00
 ;            (00FB)    00
 ;            (00FA)    01  (0x00000001表示param1的值,地址为0x0106)
 ;            (00F9)    01   
 ;            (00F8)    2F  (0x012F表示原来函数调用之前eip的地址)
 ;            (00F7)    00
 ; low address(00F6)    00  (0x0000表示原来bp的值)
 mov  bx, 0x0c                  ;cs:0143; mov ax, 000C ;BB0C00

 mov  ax, 0x1301            ;cs:0146;              ;B80113
 
 int  0x10      ;系统调用 ;cs:0149; int 10       ;CD10
 pop  bp                  ;cs:014B;              ;5D
 ret  6               ;ret指令本身会将eip弹出,所以这里sp+6,返回之后使得
                       ;sp重新执行0x0100

 
原创粉丝点击