2016-11-16 43 views
-4

我有下面的代码,我已经为它写了注释。命令程序集jmp,jne等

请告诉我,如果我在某个地方做错了什么。我很困惑所有这些jmp s。这就是为什么我把代码放在这里来清除所有这些。我写评论,我认为它是。如果你写给我的只是我的错误很容易。

TITLE SIMPLE_ADD 
CODE SEGMENT 
ASSUME CS:CODE, DS:INFORMS 
START: 
MOV AX,INFORMS ; 1)informs goes to AX 
MOV DS,AX ; 2)AX goes to DS 
MOV SI,0 ; 3)0 goes to SI 
STARTING: 
LEA DX,MESSAGE ;4)load the word MESSAGE to DX 
MOV AH,9  ;5)Give to 9 to AH 
INT 21H   ;6)Calls a subroutine. In this case it will print MESSAGE on screen 
MOV AH,8H ;7)8h goes to AH? 
INT 21H 
CMP AL,48;'0'30H ;8)Compare AL with 48? 
JB STARTING  ;9)jump if below i think it is 
CMP AL,57;'9' H 39H ;10)compare AL .I dont know 

JA STARTING ;11) jumb if above 

MOV DL,AL ;12) AL goes to DL 
MOV AH,2 ;13)2 goes to AH 
INT 21H 

; ;14) i dont know if ; this mean something or is mistake.If it is i think it might be ending 

CMP AL,48 ;15) compare 48 with AL 
JNE NEXT  ;16)jump to next 
LEA DX,ZERO ;17)load ZERO to DX 
MOV AH,9  ;18) 9 goes to AH 
INT 21H 
JMP NEXTTO ;19) beggining the jump with name NEXTTO 
NEXT: 
MOV AH,0 ;20)0 goes to AH 
MOV BL,2 ;21)2 goes to BL 
DIV BL  ;22)0 divide the 2 or 2 divide the 0 
CMP AH,0 
JNE ODDNUMBER ;23)Jump next we give the name ODDNUMBER 
LEA DX,EVENNUMBER 
MOV AH,9 
INT 21H 
JMP NEXTTO ;24) 

ODDNUMBER: 
LEA DX,ONLY 
MOV AH,9 
INT 21H 

NEXTTO: 
INC SI 
CMP SI,5 
JB STARTING 

MOV AH,4CH 
INT 21H 
CODE ENDS 

INFORMS SEGMENT 
MESSAGE DB 10,13,"NUMBER IS FROM 0-9: $" 
ZERO DB 10,13,"NUMBER IS ZERO $" 
ONLY DB 10,13,"NUMBER IS ONLY $" 
EVENNUMBER DB 10,13,"NUMBER IS EVEN $" 
INFORMS ENDS 
END START 
+0

这个问题是题外话,因为,这不是一个问题。 –

+1

装配很困难。它有助于解释你正在尝试做什么,你期望什么输出,以及实际发生了什么。 –

+0

我想解释一下jmp的使用和所有以jmp,jne等为开头的练习(如果我正在做和更多的错误请告诉我) –

回答

1
MOV DS,AX ; 2)AX goes to DS 

这是很明显的。如果你只是在学习汇编,那么我可以看到这对你来说很重要(弄清楚指令在做什么),但是当你编写汇编代码并且你已经知道已经是基础知识的时候,这些注释是没有用的。你想知道什么想法促使你将该指令放在那里,所以像“将ds设置为INFORMS段”这样的东西可以更好地保留代码背后的想法。

对于关于指令本身的推理,您应该很快就能从头部正确地获得它们的大部分内容,否则不要犹豫,请参阅英特尔的CPU指令详细说明参考指南,这是最安全和最快捷的方式。验证你所有的假设。并经常使用它(像DIVMUL可能每次检查它)。

LEA DX,MESSAGE ;4)load the word MESSAGE to DX 

它加载的是“消息”的字符串的第一个字符的存储器地址转换成dx。因此,如果INFORMS段开始,例如在物理存储器地址3000:0004,然后dx将等于4ds3000(从码的开始),和装载一个字节从ds:dx,在写为[ds:dx]英特尔的语法,将取字节值为10(这是在“MESSAGE”标签之后定义的第一个字节)。

“word MESSAGE”没有多大意义,在x86汇编中“word”通常意味着16b的值,而MESSAGE就是标签,只是一个标记进入编译器的内存。它可能在符号表中的目标文件中结束,因此链接器/ os加载器可以重定位最终指令数据以包含正确的物理地址,否则它对于CPU来说是透明的,自动编译为无。

我的意思是MESSAGE DB 10将编译为单个字节值为10,“MESSAGE”不是机器代码的直接部分。

MOV AH,9  ;5)Give to 9 to AH 
INT 21H   ;6)Calls a subroutine. In this case it will print MESSAGE on screen 

int 21h是在调用的软件中断数21h(33进制),这是在DOS主“OS”的服务处理器处理器CPU方面(DOS代表“磁盘操作系统” - 流行的替代品CP/M和其他操作系统......在有人称Linus之前,他写了商业UNIX SYSTEM V的无耻副本,并免费赠给其他人,所以现在你可以享受真正的操作系统而不是DOS,它是扩展)。

如何在使用int 21h之前设置寄存器,以及它将如何操作,这一切都由DOS供应商定义,因为操作系统的代码在那里运行。由于MS-DOS几年前很流行,你可以找到许多描述这个的在线资源,例如this one

也就是说,你应该宁愿以5) call "write string" DOS service之类的评论结束,而不是显而易见的ah = 9

MOV AH,8H ;7)8h goes to AH? 

为什么要标记问题?当然可以。它有什么问题是?您查看的文档!

ah=8是“没有回音的字符输入”服务,并将用户输入的字符返回到寄存器al中。

CMP AL,48;'0'30H ;8)Compare AL with 48? 

48是字符0的ASCII编码。对于计算机,每个信息都必须转换为位,8位形成一个字节,它可以(不是“必须”)被视为0-255范围内的数值。出于各种方便和历史的原因,当文本信息被编码时,每个字符都有1个字节(在旧的ASCII编码中 - 在现代UTF-8扩展编码中,这不再是真实的!)。并且在ASCII表中定义哪些字符与从0255的那些值配对。所以人类已知的字符编号为'0'被编码为字节值48(以位本身的形式,它是00110000)。

JB STARTING   ;9)jump if below i think it is 
CMP AL,57;'9' H 39H ;10)compare AL .I dont know 
JA STARTING   ;11) jumb if above 

因此,4行代码部分正在测试中,用户输入的字符是否在48-57(含)范围内。否则,代码将“跳转”到标签STARTING,稍后更多。此时检查ASCII表格,您会看到48-57的值覆盖了从'0''9'的所有数字字符,因此只有来自用户的数字字符输入才会使代码继续执行下一条指令。

MOV DL,AL ;12) AL goes to DL 
MOV AH,2 ;13)2 goes to AH 
INT 21H 

这将使用另一个DOS服务“output char”。它也将在al中返回最后输出的字符,因此在这种特殊情况下,这意味着al的值不会改变,并且它仍然会保存用户输入的数字。

CMP AL,48 ;15) compare 48 with AL 
JNE NEXT  ;16)jump to next 

当不相等时跳转。 cmp将从al(temp = al - 48)中减去48,丢弃结果,并根据结果设置标志寄存器。

当算术运算结果为零时,称为“零标志”或“ZF”的标志之一被设置为1。 ZF也用于JE/JNE跳转(JZ/JNZ的别名,用于更好的语义描述代码,当您在平等之后,而不是在零之后时)。所以当用户输入'0'时,cmp将设置ZF并且JNE NEXT不会跳转(因为'0'等于48),但继续下一个指令,在屏幕上显示消息“ZERO”。

DIV BL  ;22)0 divide the 2 or 2 divide the 0 

超前DIV寄存器的内容是ah=0, al=user input, bl=2DIV r8将做ax/bl,并设置:ah与其余和al与商。

如果用户确实输入了例如字符数字'7',那就是al = 55ah0。因此整个表格号码为55(ax = ah * 256 + al)。

除以2 =>ah = 1(余数),al = 27

其他代码现在应该更有意义,如果你通过关于最初部分的文本墙。因为同样的原则被反复使用。

INC SI 
CMP SI,5 
JB STARTING 

这将作为全局计数器,所以要求用户提供一个数字的5倍(码“跳跃”到STARTINGsi < 5。在此之后,代码调用DOS服务终止程序执行(正确的方法退出)

现在总算对那些跳跃:

CPU是确定性的状态机,从一个国家到另一个,所有的时间,通过芯片上的时钟同步的转换。

在这样的过渡的开始它读取来自地址cs:ipcs =代码段,ip =指令指针)的字节(一个或多个),并对其进行解码作为一个单一的指令 - 它读取那么多的字节,直到命令解码器报告指令完成。它也将更新ip的值由所使用的字节数(注意cs永远不会更新,因此在ip到达FFFFh将在下一条指令,在相同的代码段从0000环绕)。

然后它将解码后的指令分派到剩下的数百万个晶体管中去执行。

因此,在您的代码中,CPU正在按指令执行指令,一次执行一条指令,通过指令修改其内部状态,除非修改ip中的值(对于“near “跳转操作码”)或cs:ip(用于“远”跳转变体之一)。但是,这将使CPU执行新的ip值的下一条指令,从而从程序员的角度来看源代码中的“跳转”。

各种jne, je, ...指令是条件跳转(有时缩短为Jcc),只有在满足某些条件时才执行“跳转”。对于jne,助记符表示“跳转不等于”,所以跳转只在ZF为0时执行。如果您在jne之前执行了cmp,则效果可以描述为“比较两个值并在不相等时跳转”。但jne不限于使用cmp,您可以随时在代码中使用它,当您认为ZF包含一些有趣的值并且想要在其上分支时(尽管通常别名jz/jnz =“跳转时零/当不为零“对于读者来说更有意义)。

当条件不满足时,cs:ip不受影响,所以它仍然包含“下一条指令”(由CPU的指令解码器提供)的地址,因此您继续使用下一条指令读取源而不是跳转任何地方。

3

你没有写评论,您所添加的代码的副本代码

后面不写什么做,这已经写在那里。

Mov AH, 9 ; 9 goes to AH 

这不帮助任何人。

试着理解代码的作用,并写下你发现的内容。

例如

STARTING: 
LEA DX,MESSAGE ;4)load the word MESSAGE to DX 
MOV AH,9  ;5)Give to 9 to AH 
INT 21H   ;6)Calls a subroutine. In this case it will print MESSAGE on screen 
MOV AH,8H ;7)8h goes to AH? 
INT 21H 
CMP AL,48;'0'30H ;8)Compare AL with 48? 
JB STARTING  ;9)jump if below i think it is 
CMP AL,57;'9' H 39H ;10)compare AL .I dont know 
JA STARTING ;11) jumb if above 

当然没有你的意见是真的错了,只是没有帮助。让我们看看

STARTING: 

此标签的存在是有原因的,我们稍后将看到

LEA DX,MESSAGE 
MOV AH,9 
INT 21H 

这三条指令是一起的。 Int21/9打印字符串DX指向。在这种情况下,打印什么的在留言写

MOV AH,8H 
INT 21H 

INT 21/8读取从标准输入(这里从键盘最有可能)的烧焦并将其存储在AL

CMP AL,48 
JB STARTING 

我们只是读取一个char键盘,你还记得吗?如果字符小于'0',这2条指令跳回到“开始”。 JB代表“跳若跌破”(根据CMP指令之前设置的标志)...

CMP AL,57 
JA STARTING 

和这两个做同样的,如果焦炭是大于“9”。 JA是“跳,如果上述”

因此,所有的一切,代码做到这一点:

do { 
    write Message 
    read key from stdin 
} while (key < '0' or key > '9') 

或“读取键盘数字,重复进行,直到一个有效的数字被赋予”