2015-11-13 58 views
-1

我想下面的C代碼翻譯成彙編:大會翻譯

void write (int bitpos, unsigned short sample) 
{ 
    int pos = bitpos/16; 
    int posA = bitpos - pos * 16; 
    unsigned short write1 = sample >> posA; 
} 

我一直在換檔操作得到一個錯誤。我看了一本書中的一些例子,但我不明白什麼是錯的。我想這可能是因爲我想轉移的數量是一個變量。我想知道實現這個的正確方法是什麼?

這是我曾嘗試:

//int pos = bitpos/16; 
mov eax, 0 
mov eax, [bitpos] // eax= bitpos 
cdq 
mov ecx, 16   
idiv ecx  //ecx = pos 

//int posA = bitpos - pos * 16; 
mov ebx, ecx //ebx = pos 
imul ebx, 16 // ebx = pos*16 
sub eax, ebx // eax = posA 

//unsigned short write1 = sample >> posA; 
mov bx, [sample] 
shr bx, eax // This is the part that is not working. 

錯誤說:錯誤的操作數類型。錯誤代碼:C2415

+0

嘗試使用'sar'而不是'shr'。這保留了標誌。 – drum

+1

一個好的彙編程序參考應該說明唯一指示變量移位的寄存器是[in CL](http://x86.renejeschke.de/html/file_module_x86_id_285.html)。 – usr2564301

+0

你可以用'pos << 4'替換'bitpos >> 4'和'pos * 16'的'bitpos/16'。 – 2015-11-13 22:37:16

回答

2

您的write()函數沒有返回值,也沒有副作用(沒有寫入任何全局變量,沒有系統調用,只設置某些在函數返回時被丟棄的局部變量)。您可以並應該將其優化爲空函數just like gcc does

global write 
write: 
    ret 

讓我們假設你的函數返回write1變量,所以你必須計算。

gcc -Og(優化調試)使良好的可讀asm不會從內存中始終存儲/重新加載。 gcc -m32 -Og -fverbose-asm -masm=intel emits

# see the godbolt link for colour-coded mapping of source lines to asm lines 
write(int, unsigned short): 
    mov edx, DWORD PTR [esp+4] # bitpos, bitpos 
    lea eax, [edx+15] # tmp98, 
    test edx, edx # bitpos 
    cmovns eax, edx # tmp98,, bitpos, bitpos 
    sar eax, 4 # tmp99, 
    neg eax # tmp101 
    sal eax, 4 # tmp102, 
    mov ecx, eax # tmp102, tmp102 
    add ecx, edx # posA, bitpos 
    movzx eax, WORD PTR [esp+8] # D.2591, sample 
    sar eax, cl # D.2591, posA 
    ret 

注意它是如何加載函數的參數從棧中,因爲他們的功能參數,而不是全局。 (您的代碼參考[bitpos],全局,而不是返回地址後的堆棧中的第一個位置,[esp+4]。)64位ABI將args傳遞到寄存器中,以便獲得更簡潔的代碼。

條件移動代碼在那裏,因爲負數的整數除法的C語義給出不同的算術右移結果(它們以不同方式舍入)。由於idiv與換檔相比非常昂貴,因此仍然值得使用額外的指令來設置換檔。如果bitpos未簽名,則可以使用shr

通過全面優化,gcc找到了一種更有效的方法來處理事務,並將一些算術運算在一起。 (即,除以16,然後乘以16,以四捨五入到最接近的16的倍數,用單個and來實現掩蓋掉那些位)。

道德故事:你總是可以用看看編譯器輸出靈感,如何做某事,並會經常看到你最初沒有想到的技巧。