命令汇编jmp,jne等

时间:2016-11-16 12:13:40

标签: assembly x86 dos

我有以下代码,我已经为它写了评论。

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

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

2 个答案:

答案 0 :(得分:3)

你没有写评论,你添加了代码背后的代码副本

不要写什么已经完成,已经写好了。

Mov AH, 9  ; 9 goes to AH

这对任何人都没有帮助。

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

e.g。

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指向。在这种情况下,它打印在MESSAGE上写的内容

MOV AH,8H
INT 21H

int 21/8从stdin(这里很可能是键盘)中读取一个char并将其存储在AL

CMP AL,48
JB STARTING

我们刚从键盘上读过一个字母,你还记得吗?如果char小于'0',则这2条指令跳回“STARTING”。 JB代表“如果低于跳跃”(根据之前CMP指令设置的标志)......

CMP AL,57
JA STARTING

如果char大于'9',这两个也是一样的。 JA是“如果超过跳跃”

总而言之,代码就是这样做的:

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

或:“从键盘读取一个数字,重复直到有效数字被给出”

答案 1 :(得分:1)

MOV DS,AX ; 2)AX goes to DS

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

对于教学本身的推理,您应该很快就能从头脑中正确地获得大部分教学,否则请不要犹豫,参考英特尔的参考指南,并附上CPU说明书,详细说明,&#39是如何验证所有假设的最安全,最快捷的方法。并经常使用它(DIVMUL之类的东西可能每次检查一次。)

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

它加载了第一个字符的内存地址&#34; message&#34;字符串到dx。因此,如果INFORMS段例如在物理内存地址3000:0004处开始,则dx将等于4ds将为3000(从在ds:dx的英特尔语法中加载[ds:dx]的一个字节,将获取值为10的字节(这是&#34之后定义的第一个字节) ; MESSAGE&#34;标签)。

&#34;字MESSAGE&#34;并没有多大意义,在x86汇编中&#34; word&#34;通常你的意思是16b值,MESSAGE是标签,只是编译器内存的标记。它可以在符号表中的目标文件中结束,因此链接器/ os加载器可以重新定位最终的指令数据以包含正确的物理地址,但是对于CPU来说它是透明的,本身就不会编译。

我的意思是MESSAGE DB 10将编译为具有值10的单字节,&#34; MESSAGE&#34;不是机器代码的直接部分。

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就CPU软件中断号21h(十进制为33)的CPU调用处理程序而言,它在DOS中是主要的&#34; OS&#34;服务处理程序(DOS代表&#34;磁盘操作系统&#34; - CP / M和其他操作系统的流行替代品......在有人打电话给Linus之前写了无耻的商业UNIX SYSTEM V副本并将其交给其他人免费,所以现在你可以享受真正的操作系统,而不是DOS和它的扩展)。

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

那就是说你应该以{{1​​}}之类的评论结束,而不是显而易见的5) call "write string" DOS service

ah = 9

为什么标记问题?当然可以。它的问题是什么?你检查的文件!

MOV AH,8H ;7)8h goes to AH? 是&#34;字符输入没有回声&#34; service,并在注册表ah=8中返回用户输入的字符。

al

CMP AL,48;'0'30H ;8)Compare AL with 48? 是字符48的ASCII编码。对于计算机,每个信息都必须转换成比特,8比特组成一个字节,这可以(不是&#34;必须&#34;)被视为0-255范围内的数值。出于各种方便和历史原因,当文本信息被编码时,每个字符都有1个字节(旧的ASCII编码 - 在扩展编码中,如现代UTF-8,这不再是真的!)。在ASCII表中定义了哪些字符与00中的值配对。因此,人类已知为数字255的字符被编码为字节值48(以比特的形式编码为'0')。

00110000

因此4行代码部分正在测试,用户输入的字符是否在48-57(含)范围内。否则代码将跳转&#34;标记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 ,稍后再详细说明。检查ASCII表,您将看到值48-57覆盖从STARTING'0'的所有数字字符,因此只有来自用户的数字字符输入才会使代码继续下一条指令

'9'

这将使用另一个DOS服务,&#34;输出char&#34;。它也将在MOV DL,AL ;12) AL goes to DL MOV AH,2 ;13)2 goes to AH INT 21H 中返回输出的最后一个字符,因此在这种特殊情况下,它意味着al的值不会改变,它仍将保留用户输入的数字。

al

不相等时跳跃。 CMP AL,48 ;15) compare 48 with AL JNE NEXT ;16)jump to next 将从al(temp = al - 48)中减去48,丢弃结果,并根据结果设置标志寄存器。

其中一个标志叫&#34; ZERO FLAG&#34;或&#34; ZF&#34;当算术运算的结果为零时,设置为cmp。此ZF也用于1跳转(JE/JNE的别名,用于更好的语义描述代码,当您在相等之后,而不是在零之后)。因此,当用户输入JZ/JNZ时,'0'将设置ZF而cmp将不会跳转(因为&#39; 0&#39;等于48),但继续下一个说明,显示消息&#34; ZERO&#34;在屏幕上。

JNE NEXT

DIV BL ;22)0 divide the 2 or 2 divide the 0 之前,寄存器的内容为DIVah=0, al=user input, bl=2将执行DIV r8,并设置:ax/bl包含余数,ah包含商数。

如果用户确实输入了例如字符数字al,那就是'7' = al55ah。因此0整体形成数字ax(ax = ah * 256 + al)。

除以2 =&gt; 55 = ah(余数),1 = al

如果你通过这个关于初始部分的文本墙,那么其余的代码现在应该更有意义。由于相同的原则被反复使用。

27

这将作为全局计数器使用,因此在INC SI CMP SI,5 JB STARTING &lt; STARTING时,用户被要求输入5次数字(代码&#34;跳转&#34;到si。代码调用DOS服务来终止程序执行(正确的退出方式)。

现在最后关于那些跳跃:

CPU是确定性状态机,一直从一种状态进入另一种状态,通过芯片上的时钟同步这些转换。

在这种转换开始时,它从地址5cs:ip = CODE SEGMENT,cs = INSTRUCTION POINTER)读取字节,并将其解码为单个指令 - 并且它读取这么多字节,直到指令解码器报告指令完成。它还会根据使用的字节数更新ip值(请注意ip永远不会更新,因此在cs中到达FFFFh会将您从{{1}包裹起来下一条指令,在同一代码段中。)

然后它将解码后的指令发送到剩下的数百万个晶体管中,以执行它。

所以在你的代码中,CPU正在逐个指令地执行指令,通过指令修改它的内部状态,并且ip指令对内部状态几乎没有任何作用,除了修改值0000(&#34;近&#34;跳转操作码)或jmp(&#34;远&#34;跳跃变体之一)中的值。但是这将使CPU从新的ip值执行下一条指令,因此&#34;跳转&#34;从程序员的角度来源。

各种cs:ip指令是条件跳转(有时缩短为Jcc),执行&#34;跳转&#34;只有在满足某些条件时。对于ip,助记符说&#34;跳转不等于&#34;,所以只有当ZF为0时才执行跳转。如果你在jne, je, ...之前jne执行,那么效果可以描述为&#34;比较两个值并在它们不相等时跳转到某个地方#34;但是cmp并不仅限于jne的使用,当您认为ZF包含一些有趣的值并且您希望对其进行分支时,您可以随时在代码中使用它(尽管通常是别名jne =&#34;当零时/非零时跳转#34;对于源的读者更有意义。)

当条件不满足时,cmp不受影响,因此它仍然包含&#34;下一条指令&#34;的地址。 (由CPU的指令解码器提供),所以你继续用下一条指令读取源,而不是跳到任何地方。