Assembly 比较负整数时的混淆

Assembly 比较负整数时的混淆,assembly,x86-64,negative-number,yasm,Assembly,X86 64,Negative Number,Yasm,我已经开始学习汇编,对于一个示例程序我有一些困难 我编写了一个宏,可以在数组中找到最小值: %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

我已经开始学习汇编,对于一个示例程序我有一些困难

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

%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
寄存器中,我有十六进制值
0xfffffd
和十进制值
4294967293

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

你认为我的程序正确吗


提前感谢您的回答。

这是不正确的,尽管使用较小的值进行测试会隐藏错误

数组元素的类型不一致。它们是用
dd
定义的,地址计算与之一致(使用
4*索引
)<代码>cmp eax,[rbx+r12*4]也与此一致。但是
movsx eax,字[rbx+r12*4]
不是,现在突然该元素的上16位没有被使用

通过编写
mov eax、[rbx+r12*4]
可以很容易地解决这个问题


顺便说一句,您通常不应该使用
循环
,它是在大多数现代处理器上使用的

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

数组元素的类型不一致。它们是用
dd
定义的,地址计算与之一致(使用
4*索引
)<代码>cmp eax,[rbx+r12*4]也与此一致。但是
movsx eax,字[rbx+r12*4]
不是,现在突然该元素的上16位没有被使用

通过编写
mov eax、[rbx+r12*4]
可以很容易地解决这个问题


顺便说一句,您通常不应该使用
循环
,它是在大多数现代处理器上使用的

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

无论您将其解释为
-3
4294967293
或完全不同的内容(比如32个独立的真/假值),都取决于代码,代码使用该值

负整数通常使用2的补码编码,这是您用
-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寄存器中设置足够的标志,使后面的条件分支在这两种情况下都成为可能。

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

无论您将其解释为
-3
4294967293
或完全不同的内容(比如32个独立的真/假值),都取决于代码,代码使用该值

负整数通常使用2的补码编码,这是您用
-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位值,并没有其他附加信息,比如某种类型,等等