我再次在AT& T程序集中需要一些帮助,我将一些数据加载到内存中,如下(十六进制和十六进制)。
(gdb) x/8xb &buffer_in
0x8049096: 0x03 0x02 0x10 0x27 0xe8 0x03 0x64 0x00
(gdb) x/8db &buffer_in
0x8049096: 3 2 16 39 -24 3 100 0
假设第一个字节=数字计数,第二个=每个数字长度(以字节为单位),然后我们得到(第一个*第二个)字节数字。对于这个例子,3个数字,每个2个字节,第一个数字是16 39,所以一个。我想添加每个数字,所以在这种情况下,它会将0x10 + 0xe8(低字节)添加到结果[0]然后将0x27 + 0x03添加到结果[1]然后再次,结果[0] =结果[0] + 0x64,最后结果[1] =结果[1] + 0x00。
当我向已经包含0xf8的结果[0]添加0x64时,CF(进位标志)被设置,这当然很好,因为我想在下一次添加时使用这个进位结果[1]。 但问题是在下一个CMP指令之后(我将在下面的代码上标记),这个进位标志被清除,所以最终结果是0x5C2A(当我结合两个字节的结果时)应该是0x5C2B (但是由于cmp指令,进位标志没有影响加法。)
%eax - 要求数的数量
%ecx - 每个数字的长度(以字节为单位)
%esi - 在循环开始之前指向“真实”数据的第一个字节(在这种情况下为0x10)
loop1:
movl $0, %ebx
loop2:
leal (%esi, %ebx, 1), %edi
movb (%edi), %dl # %dl contain now next byte to add
adc %dl, result(%ebx) # adding to result
inc %ebx
cmp %ebx, %ecx # this comparsion clears CF flag and that's the problem
JG loop2
leal (%esi, %ecx, 1), %esi
dec %al
cmp $0, %al
JG loop1
答案 0 :(得分:1)
这通常通过调整算法逻辑来解决,以避免add
和adc
之间的任何CF更改指令,当您想要循环超过动态计数时,这看起来实际上看起来有点不可能字节。
但是,如果您要阅读有关说明INC
和DEC
的详细信息,那么有一件有趣的事情,看起来很奇怪。他们不会影响CF! (实际上它的设计就像是因为类似的用例,就像这个一样)。
所以你的代码可能看起来像这样(对不起英特尔+ NASM语法,我不喜欢AT& T,所以你自己转换,至少你会知道你理解得很好)(加上我没有调试它,所以它可能有一些bug,如果有问题,请告诉我):
; zero the result data first
movzx edx,byte [buffer_in+1] ; element length
zero_result:
dec edx
mov [result+edx],byte 0
jnz zero_result
; now sum all elements
movzx ecx,byte [buffer_in+0] ; number of elements
lea esi,[buffer_in+2] ; source data ptr
elements_loop:
movzx edx,byte [buffer_in+1] ; element length
xor ebx,ebx ; offset of byte of element = 0 AND CF=0 (!)
element_byte_loop:
mov al,[esi] ; read source byte (no CF change)
inc esi ; ++ptr (CF preserved)
adc [result+ebx],al ; add it to result with CF
inc ebx ; next offset of byte inside element (CF preserved)
dec edx ; do all bytes of element (CF preserved)
jnz element_byte_loop
; single element added to result, now repeat it for all elements
dec ecx
jnz elements_loop
答案 1 :(得分:0)
如果你只是想保存进位标志,那就有一些技巧。
推旗
pushf //save the flags
...... do stuff
popf //restore the flags
将CF保存在注册表中
//save CF in eax
sbb eax,eax //CF=1 -> CF=1, regx=-1; CF=0 -> CF=0, regx=0, clobbers other flags
//note that sbb reg, reg preserves! CF, how cool is that!
.... do stuff, do not alter eax
add eax,1 //restore CF
重写循环,使其向下计为零
loop1:
mov ebx,ecx //ebx = count
lea esi,[esi+ecx] //esi = end of buffer
neg ebx //ebx = -count
loop2:
//no need for the lea (the mov can do complex addressing)
mov dl,[esi+ebx] # %dl contain now next byte to add
adc [ecx+ebx+result],dl adding to result
inc ebx //ebx will be zero when done :-)
//no need for cmp
jnz loop2 //we only need ZF
万一你错过了。诀窍的工作原理如下
首先,我们将计数添加到基指针
接下来我们否定计数
因此,循环从basepointer+count-count = basepointer
开始
在每次迭代中,我们都会增加-count
这会在循环迭代n
中产生以下效果:address = base+count-count+n
ergo:adr = base + n
。
完成后,-count+n
将为零,我们无需执行cmp
,因为inc
会根据需要调整ZF
而不会破坏CF
}}。
请注意,我只使用Intel语法作为原则。