汇编四则计算器运行报A2006未定义符号、栈段放置错误求助
汇编四则计算器A2006未定义符号报错修复
问题基本信息
- 项目为x86汇编语言实现的支持加减乘除四则运算的计算器,代码内注释为法语,不影响逻辑理解
- 已知代码中栈段放置位置不符合规范
- 编译阶段共抛出7个A2006未定义符号错误,具体报错信息如下:
(56) error A2006: undefined symbol : scan_num (89) error A2006: undefined symbol : scan_num (100)error A2006: undefined symbol : do_plus (103)error A2006: undefined symbol : do_minus (106) error A2006: undefined symbol : do_mult (109) error A2006: undefined symbol : do_div (128) error A2006: undefined symbol : main
报错根因
A2006错误的触发逻辑是汇编器在整个代码中找不到被引用符号的定义,你的代码存在三类问题:
- 程序入口标签不匹配:代码末尾用
end main声明程序入口,但全代码仅定义了start作为入口标签,不存在main标签 - 核心功能逻辑缺失:代码中两次调用
scan_num读取用户输入的数字,四个条件跳转分别对应加减乘除四个运算分支,但scan_num过程、do_plus/do_minus/do_mult/do_div四个分支标签和对应的实现逻辑完全没有编写 - 栈段定义违规:你在代码开头写了
org 100h,这是DOS COM程序的标准写法,COM程序为单段结构,DOS加载时会自动分配栈空间,不需要用户单独定义栈段。你额外定义的SSEG栈段既没有通过assume语句关联到SS段寄存器,也没有在代码初始化阶段给SS、SP指针赋值,不符合汇编程序段定义规范。
修复步骤
- 修正入口声明:将代码最后一行的
end main修改为end start,匹配实际的入口标签,解决main未定义的报错 - 补全缺失的功能逻辑:
- 编写
scan_num近过程:实现从键盘读取多字符数字输入、转换为16位二进制数存入CX寄存器的逻辑,处理回车结束、非法字符过滤的边界情况 - 编写四个运算分支标签:
do_plus:实现num1 + num2,计算完成后调用打印过程输出结果,执行完跳转到exitdo_minus:实现num1 - num2,计算完成后调用打印过程输出结果,执行完跳转到exitdo_mult:用MUL指令实现乘法,注意16位乘法结果存放在DX:AX寄存器对中,处理好转接后输出结果,执行完跳转到exitdo_div:先判断num2是否为0,为0则跳转到错误提示分支;非0则用DIV指令计算,商存于AX、余数存于DX,处理后输出结果,执行完跳转到exit
注意:所有运算分支执行完成后必须跳转到
exit,避免代码顺序落入错误处理逻辑 - 编写
- 修正栈段定义:直接删除开头独立定义的SSEG栈段即可,符合COM程序的编写规范。如果要改为EXE格式程序,需要删除
org 100h语句,在assume中添加ss:SSEG声明,并且在start开头初始化SS为SSEG段地址、SP为栈顶偏移。
附原始代码
SSEG SEGMENT STACK DB 32 DUP("STACK---") SSEG ENDS ;===========================================================code segment assume cs:cseg, ds:cseg, es:cseg cseg segment org 100h ;---------- name "CALCULATRICE" PUTC MACRO char PUSH AX MOV AL,char MOV AH, 0Eh INT 10h POP AX ENDM jmp start ;------------- Zone de donnée msg0 db "BELLAL MOHAMED BUT1 2021/2022",0Dh,0Ah db "CALCULATOR3000 gerant les quatres opérations basiques ( + - * / )",0Dh,0Ah,"$" msg1 db 0Dh,0Ah,0Dh,0Ah, "Entrer le premier terme de l'opération: $" msg2 db "Choisissez l'opérateur à utiliser: + - * / : $" msg3 db "Entrer le second terme de l'opération: $" msg4 db 0Dh, 0Ah,"Le résultat est: $" msg5 db 0Dh, 0Ah," ",0Dh,0Ah,"$" err1 db "Saisie incorrecte",0Dh,0Ah,"$" smth db "Et .... $" opr db "?" ; variable contenant l'opérateur num1 dw ? ; variable contenant le premier terme de l'opération num2 dw ? ; variable contenant le deuxième terme de l'opération ;--------------- PROGRAMME start: mov dx, offset msg0 mov ah, 9 int 21h lea dx, msg1 mov ah, 09h ; afficher le premier message int 21h ; récupérer un nombre saisi par l'utilisateur et on le stock dans ; le registre CX call scan_num mov num1, cx ; stocker le nombre dans num1 ; nouvelle ligne putc 0Dh putc 0Ah lea dx, msg2 mov ah, 09h ; affiche le deuxième message int 21h ; récupérer l'opérateur mov ah, 1 int 21h mov opr, al ; nouvelle ligne putc 0Dh putc 0Ah cmp opr, "q" ; q pour quitter je exit cmp opr, "*" jb wrong_opr cmp opr, "/" ja wrong_opr lea dx, msg3 mov ah, 09h int 21h call scan_num mov num2, cx lea dx, msg4 mov ah, 09h int 21h ;------------- CALCULER cmp opr, "+" je do_plus cmp opr, "-" je do_minus cmp opr, "*" je do_mult cmp opr, "/" je do_div ;---------- CAS PAR DEFAUT wrong_opr: lea dx, err1 mov ah, 09h int 21h exit: lea dx, msg5 mov ah, 09h int 21h mov ah, 0 ;--------- cseg ends end main
内容的提问来源于stack exchange,提问作者BJW92i
相关产品推荐
相关产品推荐

