簡體   English   中英

AT&T大會攜帶標志

[英]AT&T Assembly carry flag

我再次需要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(低字節)添加到result [0],然后將0x27 + 0x03添加到result [1],然后再次添加result [0] = result [0] + 0x64,最后是result [1] = result [1] + 0x00。

當我在已經包含0xf8的result [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

這通常可以通過調整算法邏輯來解決,以避免在addadc之間進行任何CF更改指令,而當您想要循環動態字節數時,乍一看似乎實際上是不可能的。

但是,如果您要閱讀有關INCDEC指令的詳細信息,則有一件有趣的事情,看起來像是奇怪的不一致。 它們不影響CF! (實際上是因為類似的用例,所以才這樣設計的)。

因此,您的代碼可能看起來像這樣(對不起,Intel + NASM語法,我不喜歡AT&T,所以請自行轉換,至少您肯定會理解)(加上我沒有調試它,所以它可能有一些錯誤,如果有問題,請告訴我):

    ; 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

如果只想保存進位標志,則有一些技巧。

推標志

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語法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM