【问题标题】:Conditional jump fails in linux x86 intel syntax(NASM)linux x86 intel 语法中的条件跳转失败(NASM)
【发布时间】:2014-03-11 13:03:27
【问题描述】:

故事(我是新手): 我开始阅读有关使用著名的 nasm 汇编器在汇编(x86 英特尔)中编程的 pdf 教程,但我在执行非常基本的汇编代码时遇到了问题(受教程中关于循环的代码的启发)。

问题(JE 失败): 这个汇编代码应该从标准输入读取一个数字(一个字符(表示'0'+数字)),然后写入屏幕数字乘以“Hello world\n”。非常简单的循环:减少数字并且如果数字等于零(' 0' 不是字符的整数)跳转(je)到出口(mov eax,1\nint 0x80)。

听起来很简单,但是当我尝试执行输出时很奇怪。(真的很奇怪而且很大) 它在循环中运行多次,并在 digit 等于 '0' 时停止(很奇怪,因为在程序停止之前,条件 digit == '0' 被测试了很多次,它应该是真的)

其实我的问题是 digit == '0' 时代码跳转失败

代码(很大)

segment .text
global _start
_start:

;Print 'Input a digit:'.
mov eax,4
mov ebx,1
mov ecx,msg1
mov edx,len1
int 0x80

;Input the digit.
mov eax,3
mov ebx,0
mov ecx,dig
mov edx,2
int 0x80

;Mov the first byte(the digit) in the ecx register.
;mov ecx,0
mov ecx,[dig]

;Use ecx to loop dig[0]-'0' times.
loop:

mov [dig],ecx

mov eax,4
mov ebx,1
mov ecx,dig
mov edx,1
int 0x80

mov eax,4
mov ebx,1
mov ecx,Hello
mov edx,Hellolen
int 0x80

;For some debuging (make the loop stop until return pressed)
;mov eax,3
;mov ebx,0
;mov ecx,some
;mov edx,2
;int 0x80

;Just move dig[0](some like character '4' or '7') to ecx register and compare ecx with character '0'.
mov ecx,[dig]
dec ecx
cmp ecx,'0'

;If comparison says ecx and '0' are equal jump to exit(to end the loop)
je exit

;If not jump back to loop
jmp loop

;Other stuff ...(like an exit procedure and a data(data,bss) segment)
exit:
mov eax,1
int 0x80

segment .data
msg1 db "Input a digit:"
len1 equ $-msg1

Hello db ":Hello world",0xa
Hellolen equ $-Hello

segment .bss
dig resb 2
some resb 2

输出

输入一个数字:4 4:你好世界 3:你好世界 2:你好世界 1:你好世界 0:你好世界 ... ...(很多循环之后) ... 5:你好世界 4:你好世界 3:你好世界 2:你好世界 1:你好世界 $

这是我的问题:这段代码有什么问题? 你能解释一下吗? 而且我不需要会神奇地(无需解释)运行的替代代码,因为我尝试学习(我是新手)

这是我的问题(也是我在 Stackoverflow.com 中的第一个问题

【问题讨论】:

    标签: linux assembly nasm intel-syntax


    【解决方案1】:

    ECX 是 32 位,一个字符只有 8 位。使用 8 位寄存器,例如 CL 而不是 ECX

    【讨论】:

    • 非常感谢。有没有其他方法只是好奇?
    • 总有另一种方式 ;) 例如,您甚至不需要将其加载到寄存器中,您可以将其留在内存中并执行dec byte [dig]; cmp byte [dig], '0'
    【解决方案2】:

    正如小丑所说,ecx 是作为一个字符出现的,所以你可能应该使用 cl

    loop:
      mov [dig],cl
      ...
      mov cl,[dig]
      dec cl
      cmp cl,'0'
      jne loop
    

    您还可以使用 movzx 加载 ecx,它会清除寄存器的最高位(即零扩展加载):

      ...
      movzx ecx, byte [dig]
    loop:
      mov [dig], cl           ; store just the low byte, if you want to store
      ...
      movzx ecx, byte [dig]
      dec ecx
      cmp ecx, '0'
      jne loop
    

    请注意,通常建议您不要使用 al、bl、cl、dl 寄存器,因为它们的使用并未完全优化。这是否仍然是真的,我不知道。

    【讨论】:

    • 我在教程中找不到任何 movz。我搜索并发现“movz 指令复制 dest 操作数中的 src 操作数,并将 src 未提供的其余位填充零 (0)。 “。这对小端或大端有什么影响?因为在两个相同的位位置都会被填充吗?
    • movz 首先以小端序加载 1、2 或 4 个字节(在 x86 上),然后清除其他位。所以“z”不会影响数据的字节序(即它不会加载高位字节。)
    • 英特尔语法助记符是movzx,而不是movz。在byte 大小说明符之后没有:
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-26
    • 1970-01-01
    • 1970-01-01
    • 2016-01-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多