AT& T Assembly带有标志

时间:2017-05-24 09:01:32

标签: assembly flags att carryflag

我再次在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

2 个答案:

答案 0 :(得分:1)

这通常通过调整算法逻辑来解决,以避免addadc之间的任何CF更改指令,当您想要循环超过动态计数时,这看起来实际上看起来有点不可能字节。

但是,如果您要阅读有关说明INCDEC的详细信息,那么有一件有趣的事情,看起来很奇怪。他们不会影响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语法作为原则。