我已经开始研究汇编,并且在示例程序方面有些困难。
我写了一个可以在数组中找到最小值的宏:
@Injectable
该程序成功编译,但是当我调试它(使用DDD)时,在%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
寄存器中,我有一个十六进制值eax
和一个十进制值0xFFFFFFFD
。
但是,如果我使用计算器4294967293
的确是0xFFFFFFFD
,那是正确的值。
您认为我的程序正确吗?
预先感谢您的回答。
答案 0 :(得分:4)
这是不正确的,尽管用较小的值进行测试会隐藏该错误。
将数组的元素视为哪种类型存在不一致。它们用dd
定义,并且地址计算与此一致(使用4*index
)。 cmp eax, [rbx+r12*4]
也与此一致。但是movsx eax, word[rbx+r12*4]
不是,现在突然不使用元素的高16位。
通过写mov eax, [rbx+r12*4]
可以很容易地解决此问题。
通常您不应该使用loop
的方式,在大多数现代处理器上都是quite slow。
答案 1 :(得分:3)
0xFFFFFFFD
是32位值1111_1111_1111_1111_1111_1111_1111_1101
,这可能是CPU物理内部的最接近比喻(32个具有不同电流水平的单元或编码逻辑值为0或1的磁极)。
您是否将解释为-3
或4294967293
还是完全不同的东西(例如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寄存器中设置足够的标志,以使这两种情况都可以进行以后的条件分支。