[英]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
這通常可以通過調整算法邏輯來解決,以避免在add
和adc
之間進行任何CF更改指令,而當您想要循環動態字節數時,乍一看似乎實際上是不可能的。
但是,如果您要閱讀有關INC
和DEC
指令的詳細信息,則有一件有趣的事情,看起來像是奇怪的不一致。 它們不影響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.