Masm(611) 调用 第三方c语言函数(汇编调用第三方c语言函数库)

一开始的代码:

void print(){
	printf("hello hairi");
}

lib1的代码

include Lib1.lib
data segment    ;定义数据段
    infon db 0dh,0ah,'Please input a year: $'	;infon ,双字节,回车换行,内容
    Y db 0dh,0ah,'This is a leap year! $'	;y ,双字节,回车换行,内容
    N db 0dh,0ah,'This is not a leap year! $' 	;n ,双字节,回车换行,内容($是结束符)
    w dw 0		;w为双字类型
    buf db 8		;开辟8个双字节类型的缓冲区,未赋值
        db ?		
        db 8 dup(?)		
data ends

stack segment stack
    db 200 dup(0)	;开辟200个双字节类型的存储空间。(保护现场用到)
stack ends


code segment
          assume ds:data,ss:stack,cs:code
    start:mov ax,data	;寄存器间的数据交换,把data给了数据段
          mov ds,ax
          
         invoke print,NULL		;添加hello hairi
	
          lea dx,infon  ;在屏幕上显示提示信息
          mov ah,9
          int 21h

          lea dx,buf    ;从键盘输入年份字符串
          mov ah,10
          int 21h
          
          mov cl, [buf+1] 	;把buf+1地址指向的内容给cl,buf长度
          lea di,buf+2		;把buf+2的地址给di,buf偏移地址
          call datacate  ;调用函数datacate,传递参数
          call ifyears	;调用函数ifyears,由参数判断是否为闰年
          jc a1			;若产生进位就跳到a1处
          
          lea dx,n		;dx加载n的地址'This is not a leap year!'
          mov ah,9		;显示dx内的内容
          int 21h
          jmp exit		;跳到exit
    a1:   lea dx,y		;dx加载y的地址'This is a leap year!'
          mov ah,9
          int 21h
    exit: mov ah,4ch	;结束本程序,返回 DOS 操作系统
          int 21h
       
 
;实现将字符串的闰年转换为数字存储在ax中
datacate proc near;	;段内调用,子函数1
          push cx;      ;保护现场                                               
          dec cx		
          lea si,buf+2	;把buf+2的地址给si
     tt1: inc si		;移动到字符串指定位置
          loop tt1		;循环函数是个递增函数, loop指令的格式是:loop标号,cpu执行loop指令的时候,要进行两步操作
						;1:(cx)=(cx)-1    
						;2:判断cx中的值,不为零则转至标号处执行,如果为零,则向下执行
          ;lea si,cx[di]
          pop cx		;恢复现场
     
      
          mov dh,30h	
          mov bl,10		;乘数设置为10
          mov ax,1		
      l1: push ax		;保护现场
          sub  byte ptr [si],dh		;没有寄存器参与的内存单元访问指令(DMA),si-dh保存在si中
          mul  byte ptr [si]		;没有寄存器参与的内存单元访问指令(DMA),ax*si,结果放在eax中,这里的寄存器si是16位,被乘数在ax中也是16位。
          							;MUL r/m(寄存器或者内存)  ;mul是字内乘法,把si对应的地址内一个字的长度赋给
									;如果参数是 r8/m8,   将把 AL 做乘数, 结果放在 AX
									;如果参数是 r16/m16, 将把 AX 做乘数, 结果放在 EAX
									;如果参数是 r32/m32, 将把 EAX 做乘数, 结果放在 EDX:EAX
          add w,ax		;w+ax,结果存入w,存入的是数字
          pop ax		;恢复现场
          mul bl		;bl*al,结果存放在ax中
          dec si		;si中的内容减一
          loop l1		;l1循环,cx判断次数
          ret
 datacate endp

;实现ax中年份的判断
   ifyears proc near		;段内调用,子函数2
           push  bx 		;保护现场(保护谁,就用到谁)
           push  cx
           push  dx
           mov ax,w			;把w值赋给cx,w值为
           mov   cx,ax		;把ax值赋给cx
           mov  dx,0		
           mov  bx,4		;ax/4
           div  bx			;ax/bx,结果在ax中,余数在dx中
           					;如果除数是8位,那么除法的结果AL保存商,AH保存余数,
       						;如果除数是16位,那么除法的结果 AX保存商,DX保存余数。
           cmp  dx,0		;比较余数和0,结果存入cf标志位(进位标志位)
           jnz  lab1		;如果非0,跳转到lab1处
           mov   ax,cx		
           mov  bx,100		;ax/100
           div  bx			
           cmp dx,0			;比较余数和0,结果存入cf标志位(进位标志位)
           jnz  lab2		;如果非0,跳到lab2
           mov  ax,cx		
           mov bx,400		;ax/400
           div  bx			
           cmp  dx,0		;比较余数和0,结果存入cf标志位(进位标志位)
           jz  lab2			;cf=0跳到lab2
     lab1: clc				;清除cf标志位,设置cf=0
           jmp lab3			;跳到lab3
     lab2: stc				;cf置1
     lab3: pop  dx			;恢复现场
           pop  cx		
           pop  bx
           ret
   ifyears endp
code ends
   end start

报错:
错误是指invoke语句不识别
error A2105:错误是指invoke语句不识别

可能原因:路径错误,缺少函数声明
注:Includelib的默认搜索路径是c盘(mount 指定的c盘)
注:Masm.exe和link.exe不需要依赖include和lib文件夹,移除两个文件夹的内容后依旧可以编译链接

修改代码如下:

includelib Lib1.lib
extrn print:far
data segment    ;定义数据段
    infon db 0dh,0ah,'Please input a year: $'	;infon ,双字节,回车换行,内容
    Y db 0dh,0ah,'This is a leap year! $'	;y ,双字节,回车换行,内容
    N db 0dh,0ah,'This is not a leap year! $' 	;n ,双字节,回车换行,内容($是结束符)
    w dw 0		;w为双字类型
    buf db 8		;开辟8个双字节类型的缓冲区,未赋值
        db ?		
        db 8 dup(?)		
data ends

stack segment stack
    db 200 dup(0)	;开辟200个双字节类型的存储空间。(保护现场用到)
stack ends


code segment
          assume ds:data,ss:stack,cs:code
    start:mov ax,data	;寄存器间的数据交换,把data给了数据段
          mov ds,ax
          
         call print		;添加hello hairi
	
          lea dx,infon  ;在屏幕上显示提示信息
          mov ah,9
          int 21h

          lea dx,buf    ;从键盘输入年份字符串
          mov ah,10
          int 21h
          
          mov cl, [buf+1] 	;把buf+1地址指向的内容给cl,buf长度
          lea di,buf+2		;把buf+2的地址给di,buf偏移地址
          call datacate  ;调用函数datacate,传递参数
          call ifyears	;调用函数ifyears,由参数判断是否为闰年
          jc a1			;若产生进位就跳到a1处
          
          lea dx,n		;dx加载n的地址'This is not a leap year!'
          mov ah,9		;显示dx内的内容
          int 21h
          jmp exit		;跳到exit
    a1:   lea dx,y		;dx加载y的地址'This is a leap year!'
          mov ah,9
          int 21h
    exit: mov ah,4ch	;结束本程序,返回 DOS 操作系统
          int 21h
       
 
;实现将字符串的闰年转换为数字存储在ax中
datacate proc near;	;段内调用,子函数1
          push cx;      ;保护现场                                               
          dec cx		
          lea si,buf+2	;把buf+2的地址给si
     tt1: inc si		;移动到字符串指定位置
          loop tt1		;循环函数是个递增函数, loop指令的格式是:loop标号,cpu执行loop指令的时候,要进行两步操作
						;1:(cx)=(cx)-1    
						;2:判断cx中的值,不为零则转至标号处执行,如果为零,则向下执行
          ;lea si,cx[di]
          pop cx		;恢复现场
     
      
          mov dh,30h	
          mov bl,10		;乘数设置为10
          mov ax,1		
      l1: push ax		;保护现场
          sub  byte ptr [si],dh		;没有寄存器参与的内存单元访问指令(DMA),si-dh保存在si中
          mul  byte ptr [si]		;没有寄存器参与的内存单元访问指令(DMA),ax*si,结果放在eax中,这里的寄存器si是16位,被乘数在ax中也是16位。
          							;MUL r/m(寄存器或者内存)  ;mul是字内乘法,把si对应的地址内一个字的长度赋给
									;如果参数是 r8/m8,   将把 AL 做乘数, 结果放在 AX
									;如果参数是 r16/m16, 将把 AX 做乘数, 结果放在 EAX
									;如果参数是 r32/m32, 将把 EAX 做乘数, 结果放在 EDX:EAX
          add w,ax		;w+ax,结果存入w,存入的是数字
          pop ax		;恢复现场
          mul bl		;bl*al,结果存放在ax中
          dec si		;si中的内容减一
          loop l1		;l1循环,cx判断次数
          ret
 datacate endp

;实现ax中年份的判断
   ifyears proc near		;段内调用,子函数2
           push  bx 		;保护现场(保护谁,就用到谁)
           push  cx
           push  dx
           mov ax,w			;把w值赋给cx,w值为
           mov   cx,ax		;把ax值赋给cx
           mov  dx,0		
           mov  bx,4		;ax/4
           div  bx			;ax/bx,结果在ax中,余数在dx中
           					;如果除数是8位,那么除法的结果AL保存商,AH保存余数,
       						;如果除数是16位,那么除法的结果 AX保存商,DX保存余数。
           cmp  dx,0		;比较余数和0,结果存入cf标志位(进位标志位)
           jnz  lab1		;如果非0,跳转到lab1处
           mov   ax,cx		
           mov  bx,100		;ax/100
           div  bx			
           cmp dx,0			;比较余数和0,结果存入cf标志位(进位标志位)
           jnz  lab2		;如果非0,跳到lab2
           mov  ax,cx		
           mov bx,400		;ax/400
           div  bx			
           cmp  dx,0		;比较余数和0,结果存入cf标志位(进位标志位)
           jz  lab2			;cf=0跳到lab2
     lab1: clc				;清除cf标志位,设置cf=0
           jmp lab3			;跳到lab3
     lab2: stc				;cf置1
     lab3: pop  dx			;恢复现场
           pop  cx		
           pop  bx
           ret
   ifyears endp
code ends
   end start
      

在这里插入图片描述
编译成功,链接出现问题
可能原因:lib库位置出错,16位编译器无法编译32位的lib库

改用Masm32 edit

使用Masm32 edit,依然报错:
在这里插入图片描述
原因:Masm611的语法和masm32的语法不同。
使用masm生成的obj进行link,依然报错:
在这里插入图片描述
原因:使用16位生成的obj去进行32位的link操作不合理

猜你喜欢

转载自blog.csdn.net/hairi1234/article/details/85229760
今日推荐