1

我已经开始学习汇编,但我对示例程序有些困难。

我写了一个宏,可以找到数组中的最小值:

%macro min 3    
    mov ecx, dword[%2]
    mov r12, 0
    lea rbx, [%1]
    movsx eax, word[rbx+r12*4] ; inizializza il minimo con il primo elemento dell'array

%%minLoop:
    cmp eax, [rbx+r12*4]
    jl %%notNewMin
    movsx eax, word[rbx+r12*4]

    %%notNewMin:
        inc r12

    loop %%minLoop
    mov [%3], eax

%endmacro

section .data
EXIT_SUCCESS equ 0
SYS_exit     equ 60

list1 dd 4, 5, 2, -3, 1
len1 dd 5
min1 dd 0

section .text
global _start

_start:
    min list1, len1, min1
last:
    mov rax, SYS_exit ; exit
    mov rdi, EXIT_SUCCESS ; success
    syscall

该程序成功编译,但是当我调试它(​​使用 DDD)时,在eax寄存器中我0xFFFFFFFD4294967293.

但是,如果我使用计算器,这0xFFFFFFFD确实-3是正确的值。

在您看来,我的程序是否正确?

提前感谢您的回答。

4

2 回答 2

4

这是不正确的,尽管用小值测试它会隐藏错误。

数组元素的类型不一致。它们是用 定义的dd,并且地址计算与其一致(使用4*index)。cmp eax, [rbx+r12*4]也与此一致。但movsx eax, word[rbx+r12*4]不是,现在突然不使用元素的高 16 位。

这可以很容易地通过编写mov eax, [rbx+r12*4]来解决。

顺便说一句,您通常不应该使用loop,它在大多数现代处理器上都非常慢。

于 2018-08-09T16:30:13.667 回答
3

0xFFFFFFFD是 32 位值1111_1111_1111_1111_1111_1111_1111_1101,这可能是 CPU 内部物理的最接近的隐喻(32 个具有不同电流水平的单元或编码逻辑值 0 或 1 的磁极)。

您是否将其解释-34294967293完全不同的东西(比如说 32 个独立的真/假值)取决于使用该值的代码。

负整数通常使用二进制补码编码,您正在观察您的-3值。

调试器不知道您将值解释为有符号还是无符号(除非您通过格式化参数指定它),因此它将选择一种格式并像这样显示,在您的情况下为无符号 32 位值,这意味着您看到4294967293而不是-3,但按位这两者是相同的,并且对于像add/sub/cmp/test/...该值一样的算术指令也是相同的,只有以下代码对结果(和标志)的解释将决定该值是“有符号”还是“无符号”。

符号本身不是编码信息的一部分,或者有时将最高位视为“符号”位,因为所有负值都设置了最高位,但这就是带符号的 8 位值只能存储值 -128 的原因。 .+127,而无符号的 8 位值可以存储值 0..+255(即两种解释正好涵盖 256 个不同的值,因为 8 位可以产生 256 种不同的 0/1 模式组合,但有符号的解释“开始”于“ 0x80 = -128”,而无符号解释“开始”在“0x00 = 0”,而 0x80 已经被解释为 +128。但是这两种解释都只使用 8 位值,没有其他附加信息,比如某种类型等。

例如

cmp    eax, ebx   ; check if eax is bigger than ebx
; now if the values were meant as unsigned, then use "ja" branch
ja     eax_is_bigger_as_unsigned
; but if you meant the values as signed, then you should use "jg" (testing different flags)
jg     eax_is_bigger_as_signed

因此,cmp它本身并不关心您如何解释该位模式,它会在 EFLAGS 寄存器中设置足够的标志,以使后面的条件分支在这两种情况下都成为可能。

于 2018-08-09T17:49:02.793 回答