《汇编语言 基于x86处理器》第十三章高级语言接口部分的代码 part 2

▶ 书中第十三章的程序,主要讲了汇编语言和 C/++ 相互调用的方法

● 代码,汇编中调用 C++ 函数

 1 ; subr.asm
 2 INCLUDE Irvine32.inc
 3 
 4 askForInteger PROTO C
 5 showInt PROTO C, value:SDWORD, outWidth:DWORD
 6 
 7 OUTPUT_WIDTH = 8
 8 MAX_POWER = 10
 9 
10 .data
11 intVal DWORD ?
12 
13 .code
14 SetTextOutColor PROC C, color:DWORD
15     mov     eax, color
16     call    SetTextColor
17     call    Clrscr
18     ret
19 SetTextOutColor ENDP
20 
21 DisplayTable PROC C
22     INVOKE askForInteger        ; 调用 C++ 函数输入整数
23     mov    intVal, eax          ; 保存返回值
24     mov    ecx, MAX_POWER
25 
26 L1: 
27     push    ecx
28     shl     intVal, 1                       ; 每次乘以 2
29     INVOKE  showInt, intVal, OUTPUT_WIDTH   ; 调用 C++ 函数显示结果
30     call    Crlf
31     pop     ecx
32     loop    L1
33 
34     ret
35 DisplayTable ENDP
36 
37 END
 1 // main.cpp
 2 #include <iostream>
 3 #include <iomanip>
 4 using namespace std;
 5 
 6 extern "C"  // 声明外部 asm 过程和 C++ 函数
 7 {        
 8     void SetTextOutColor(unsigned color);   // 设置终端字体和背景颜色
 9     void DisplayTable();                    // 显示表格
10     
11     int askForInteger();                    // 输入整数
12     void showInt(int value, int width);     // 按宽度 width 显示数字 value
13 }
14 
15 int main()
16 {
17     SetTextOutColor(0x1E);                  // 蓝底黄字
18     DisplayTable();
19 
20     getchar();
21     getchar();
22     return 0;
23 }
24 
25 int askForInteger()
26 {
27     int n;
28     cout << "Target integer [1, 90000]: ";
29     cin >> n;
30     return n;
31 }
32 
33 void showInt(int value, int width)
34 {
35     cout << setw(width) << value;
36 }

■ 输出结果

● 代码,汇编调用 C/C++ 库函数和自定义函数。有个奇怪的 bug,scanf 至少要在主函数中用一次,否则汇编的目标文件找不到,暂时不明。

 1 ; asmMain.asm
 2 INCLUDE Irvine32.inc
 3 
 4 printSingle PROTO C, aSingle:REAL4, precision:DWORD ; 声明外部函数(库函数不用声明)
 5 
 6 TAB = 9
 7 
 8 .code
 9 asmMain PROC C                              ; 程序入口
10 
11 .data                                       ; 测试 printf
12 format BYTE "%.2f",TAB,"%.3f",0dh,0ah,0
13 val1 REAL8 456.789
14 val2 REAL8 864.231
15 .code
16 INVOKE printf, ADDR format, val1, val2      ; 调用 printf
17                                             ; 书本注释曰,不能用 INVOKE ptrintf 来显示 REAL4 型变量?
18 
19 .data                                       ; 测试 scanf
20 strSingle BYTE "%f",0
21 strDouble BYTE "%lf",0
22 float1 REAL4 1234.567
23 double1 REAL8  1234567.890123
24 
25 .code
26 INVOKE scanf, ADDR strSingle, ADDR float1   ; 调用 scanf,覆盖掉原本的值
27 INVOKE scanf, ADDR strDouble, ADDR double1
28 
29 .data                                       ; 测试栈传参 printf 和自定义函数
30 valStr BYTE "float1 in ASM = %.3f", 0dh, 0ah, 0
31 
32 .code
33     fld    float1                           ; 将 float1 转存到 FPU 栈中
34     sub    esp,8                            ; 指到栈的高位
35     fstp    qword ptr [esp]                 ; 当成 double 取出
36     push    OFFSET valStr                   ; 栈传参来调用 printf
37     call    printf
38     add    esp,12    
39     INVOKE printSingle, float1, 3           ; 自定义外部函数来显示 float1
40 
41     call    Crlf        
42     ret
43 asmMain ENDP
44 
45 END
 1 // main.cpp
 2 #define _CRT_SECURE_NO_WARNINGS // 关闭 MVC++ 关于 scanf 被 scanf_s 取代的警告
 3 
 4 #include <stdio.h>
 5 #include <string>
 6 #include <strstream>
 7 
 8 using namespace std;
 9 
10 extern "C"
11 {
12     void asmMain();
13     void printSingle(float d, int precision);
14 }
15 
16 void printSingle(float d, int precision)
17 {
18     strstream temp;
19     temp << "float1 in C++ = %." << precision << "f" << '';
20     printf(temp.str(), d);
21 }
22 
23 int main()
24 {
25     asmMain();
26     scanf("");  // 如果没有这一句就会报错:LNK2019,无法解析的外部符号 _scanf,该符号在函数 _asmMain 中被引用
27     getchar();
28     getchar();
29     return 0;
30 }

■ 程序输出

456.79  864.231
123.456
123456789.123456789
float1 in ASM = 123.456
float1 in C++ = 123.456

● 代码,汇编调用 C 库函数,system 和 file 相关。还是有那个要在主函数里用一次 printf 和 scanf 的问题。

 1 ; asmMain.asm
 2 .586
 3 .MODEL flat, C
 4 
 5 system PROTO, pCommand:PTR BYTE                                 ; 声明一堆库函数
 6 printf PROTO, pString:PTR BYTE, args:VARARG
 7 scanf  PROTO, pFormat:PTR BYTE,pBuffer:PTR BYTE, args:VARARG
 8 fopen  PROTO, mode:PTR BYTE, filename:PTR BYTE
 9 fclose PROTO, pFile:DWORD
10 
11 BUFFER_SIZE = 5000
12 .data
13 str1 BYTE "cls", 0
14 str2 BYTE "dir/w", 0
15 str3 BYTE "Enter the name of a file: ", 0
16 str4 BYTE "%s", 0
17 str5 BYTE "Failed to open the file", 0dh, 0ah, 0
18 str6 BYTE "Succeeded to open the file", 0dh, 0ah, 0
19 modeStr BYTE "r",0
20 
21 fileName BYTE 60 DUP(0)
22 pBuf  DWORD ?
23 pFile DWORD ?
24 
25 .code
26 asm_main PROC
27     INVOKE  system,ADDR str1                    ; cls
28     INVOKE  system,ADDR str2                    ; dir
29     
30     INVOKE  printf,ADDR str3                    ; 提示信息
31     INVOKE  scanf, ADDR str4, ADDR fileName     ; 输入文件名
32 
33     INVOKE  fopen, ADDR fileName, ADDR modeStr  ; 尝试打开文件
34     mov     pFile, eax
35 
36     .IF eax == 0
37         INVOKE printf,ADDR str5
38         jmp quit
39     .ELSE
40         INVOKE printf,ADDR str6
41     .ENDIF
42     INVOKE fclose, pFile
43 
44 quit:
45     ret
46 asm_main ENDP
47 END 
 1 // main.cpp
 2 #define _CRT_SECURE_NO_WARNINGS
 3 #include <stdio.h>
 4 
 5 extern "C" void asm_main();
 6 
 7 void main()
 8 {
 9     asm_main();
10     scanf("");
11     printf("");
12     getchar();
13     getchar();
14 }
原文地址:https://www.cnblogs.com/cuancuancuanhao/p/9696552.html