汇编语言用Extern伪指令新建模块[附带实例]


本节主要讲解使用传统的 EXTERN 伪指令引用位于不同模块中的函数。

PromptForIntegers

jprompt.asm 是 PromptForIntegers 过程的源代码文件。它显示提示要求用户输入三个整数,调用 Readlnt 获取数值,并将它们插入数组:
;提示整数输入请求    (_prompt.asm)
INCLUDE Irvine32.inc
.code
;--------------------------------
PromptForIntegers PROC
;提示用户为数组输入整数,并用
;用户输入填充该数组。
;接收:
;    ptrPrompt:PTR BYTE    ;提示信息字符串
;    ptrArray:PTR DWORD    ;数组指针
;    arraySize:DWORD       ;数组大小
;返回:无
;--------------------------------
arraySize EQU [ebp+16]
ptrArray EQU [ebp+12]
ptrPrompt EQU [ebp+8]
    enter 0,0
    pushad                     ;保存全部寄存器
    mov ecx,arraySize
    cmp    ecx,0               ;数据大小WO?
    jle    L2                  ;是:退出
    mov edx,ptrPrompt          ;提示信息的地址
    mov esi,ptrArray
L1: call WriteString           ;显示字符串
    call ReadInt               ;将整数读入EAX
    call Crlf                  ;换行
    mov [esi],eax              ;保存入数组
    add esi,4                  ;下一个整数
    loop L1
L2: popad                      ;恢复全部寄存器
    leave 
    ret 12                     ;恢复堆栈
PromptForIntegers ENDP
END

ArraySum

_arraysum.asm 模块为 ArraySum 过程,计算数组元素之和,并用 EAX 返回计算结果:
;ArraySumit程    (_arrysum.asm)
INCLUDE Irvine32.inc
.code
;----------------------------------------------   
ArraySum PROC
;计算32位整数数组之和。
;接收:
;    ptrArray    ;数组指针
;    arraySize    ;数组大小(DWROD)
;返回:EAX = 和数
;----------------------------------------------   
ptrArray EQU [ebp+8]
arraySize EQU [ebp+12]
    enter 0,0
    push ecx                      ;EAX 不入栈
    push esi
   
    mov    eax, 0                 ;和数清零
    mov    esi, ptrArray
    mov    ecx,arraySize
    cmp    ecx, 0                 ;数组大小WO?
    jle    L2                     ;是:退出
L1: add    eax, [esi]             ;将每个整数加到和数中
    add    esi,4                  ;指向下一个整数
    loop L1                       ;按数组大小重复

L2: pop esi
    pop ecx                       ;用EAX返回和数
    leave
    ret    8                      ;恢复堆栈
ArraySum ENDP
END

DisplaySum

_display.asm 模块为 DisplaySum 过程,显示标号和和数的结果:
;DisplaySum 过程    (_display.asm)
INCLUDE Irvine32.inc
.code
;-----------------------------------------
DisplaySum PROC
;在控制台显示和数。
;接收:
;    ptrPrompt      ;提示字符串的偏移量
;    theSum         ;数组和数(DWROD)
;返回:无
;-----------------------------------------
theSum EQU [ebp+12]
ptrPrompt EQU [ebp+8]
    enter 0,0
    push eax
    push edx

    mov edx,ptrPrompt                           ;提示字符串的指针
    call WriteString
    mov eax,theSum
    call Writelnt                               ;显示 EAX
    call Crlf

    pop edx
    pop eax
    leave
    ret 8                                        ;恢复堆栈
DisplaySum ENDP
END

Startup 模块

Sum_main.asm 模块为启动过程 (main)。其中的 EXTERN 伪指令指定了三个外部过程。为了使源代码更加友好,用 EQU 伪指令再次定义了过程名:

ArraySum           EQU ArraySum@0
PromptForIntegers  EQU PromptForIntegers@0
DisplaySum         EQU DisplaySum@0

每次过程调用之前,用注释说明了参数顺序。该过程使用 STDCALL 参数传递规范:
;整数求和过程(Sum_main.asm)
;多模块示例
;本程序由用户输入多个整数,
;将它们存入数组,计算数组之和,
;并显示和数。
INCLUDE Irvine32.inc

EXTERN PromptForIntegers@0:PROC
EXTERN ArraySum@0:PROC, DisplaySum@0:PROC
;为方便起见,重新定义外部符号
ArraySum          EQU ArraySum@0
PromptForIntegers EQU PromptForIntegers@0
DisplaySum        EQU DisplaySum@0
;修改 Count 来改变数组大小:
Count = 3

.data
prompt1 BYTE "Enter a signed integer: ",0
prompt2 BYTE "The sum of the integers is: ",0
array DWORD Count DUP(?)
sum DWORD ?
.code
main PROC
    call Clrscr
;PromptForIntegers (addr prompt1, addr array, Count)
    push Count
    push OFFSET array
    push OFFSET prompt1
    call PromptForIntegers
;sum = ArraySum(addr array, Count)
    push Count
    push OFFSET array
    call ArraySum
    mov sum,eax
;DisplaySum(addr prompt2, sum)
    push sum
    push OFFSET prompt2
    call DisplaySum
    call Crlf
    exit
main ENDP
END main