簡體   English   中英

大量轉移-組裝

[英]Shifting a huge number - assembly

我有大量加載到堆棧上的文件,我使用eax訪問。 它不能存儲在寄存器中。 我使用eax只是指向它的地址(數字是自然類型,這意味着前4個字節包含符號,接下來的4個字節包含長度,其他則為實際值)。

我必須改變它的edx時間。 我正在考慮從LSB一位開始移位(最多8次/字節),然后將這些位復制到下一個字節中。 為此,我必須首先移動下一個字節,依此類推,直到MSB位置+ 1(最壞的情況),或者直到完成所有移位並且沒有進位標志為止。 PS我顯然是在這種特殊情況下談論shl但是shr情況幾乎相同。

有沒有更簡單的解決方案?

經典的8位時代思想是使用由DEC counter + JNZ交錯的RCL(帶進位向左旋轉)-您可以暫停一秒鍾,最后欣賞一下,為什么x86 DEC/INC指令僅影響零標志,但不影響進位(謎底已解決) )。

因此,代碼將遵循以下幾行:

    mov   edi,address_of_last_byte
    mov   edx,count_of_bytes
    mov   cl,1
    clc   ; clear CF
loop_1_bit_left:
    rcl   byte [edi],cl    ; CF -> LSB, MSB -> CF
    dec   edi    ; preserves CF! Goes from last byte to first one
    dec   edx    ; preserves CF! Decrement counter
    jnz   loop_1_bit_left  ; till whole buffer is shifted
    ; CF has last bit, will be thrown away unless you do something about it

現在這有很多不足之處...

如何保存緩沖區的MSB? 我將首先計算移位后所需的緩沖區大小(new_length = arg_length +(shift + 7)/ 8)。 並將輸入復制到其中,然后不移位arg_length個字節,而是移位new_length個字節,從而解決了MSB截斷的問題。

但是還有另一個問題,性能。 不幸的是,現代x86 CPU上的rcl速度很慢,因此以這種方式進行315位移位是非常糟糕的主意。 但是您不必。 您可以僅通過將已經減少39個字節的輸入數(朝開始處)復制到new_length緩沖區中,來進行312位移位,然后通過上面的循環將剩下的3位進行一次移位。

另外,如果您將足夠填充輸出緩沖區,則可以使用dword / qword rcl變體(32b / 64b代碼)來同時處理更多字節。 (實際上,根據您的描述,不清楚您的代碼由誰負責分配,如果您的代碼將以某種方式將其返回到堆棧上(??我不確定根據移位量動態增長的緩沖區在哪種ABI可能實現),或者將其分配在堆上,再在頂部再添加幾個字節,因此您可以在值的最后一個常規字節之后修改幾個字節,並且可以改為使用dword / qword以及超過4 / 8B對齊的(!)地址。


編輯: word / dword引用的變種rcl / rcr在陣列整個大數量以下的x86小端的方式,只有當將正常工作,且環路下面的正確++ / -方向(位b0-7在字節數組中的偏移量為+0,例如b80-b87的位在偏移量為+10時,右移將從MSB(+10)b87移向LSB(+0)b0)。 我的第一個byte [edi]示例期望它采用大端方式,其中MSB從偏移量+0開始,而LSB以+結尾,因此可以按人的順序查看這些位b87 .. b0,little endian具有每個字節組(b7 .. b0 b15 .. b8 ... ... ... b87 ... b80)在視覺上“反轉”了……至少我是這樣認為的,現在我開始變得如此困惑。 只需以一種方式編寫代碼,為簡單的極端情況創建單元測試,並驗證結果並對其進行修復以產生您所期望的結果。 :D


只要確保您在這種情況下不要通過sub edi,4sub rdi,8 )更新edi ,因為那樣會破壞CF內容,因此改用lea edi[edi-4]通過尋址模式進行簡單計算的方法。 並將計數器調整為正確的/4 || /8 /4 || /8值。

為了獲得最佳性能,可能仍然值得一口氣將1-7位移位:對於左1位,您可以保留rcl版本,對於2-7位移位,某些掩蔽/運算值的變體將按目標量單次移位例如,使用32b寄存器來處理16b的緩沖區讀/寫操作,並將移出的位保留在上半部分。 或者,如果您走得那么遠,也許它與shl/and/or 1位變體是否兼容,是否不比rcl快。 由於編譯器未使用rcl ,因此特定的CPU可能會比單個rcl更喜歡一些shl/and/or指令。


有趣的事實:我完全獨自編寫的第一個Z80匯編代碼就是這樣做的,將一個巨大的內存區域向左(向右)移動了一點。 由於該巨大的存儲區實際上是ZX Spectrum計算機的視頻內存,因此可以有效地左右移動圖像1個像素(ZX每個像素使用1位)。

而且我沒有意識到可以從一個旋轉到另一個旋轉使用CF,因此我通過分別屏蔽位,將其復制到另一個寄存器,然后從那里恢復到新的字節等方式來做到這一點。

所以我寫了它,運行它(由於錯誤而重置了ZX),修復了該錯誤,運行了它,並觀察了圖像的移動方式……比我預期的慢了10倍(每秒約3幀) “全能的快速匯編代碼”。 然后我的一個朋友確實向我展示了如何旋轉它,這使代碼朝着20 FPS的方向運行(這仍然使我意識到,即使“快速匯編”也不是無限的,我必須花很多時間來編寫代碼,在ZX的屏幕上看到任何看起來不錯的東西)。

我寧願ROL或ROR值,切掉翻轉的位,並將它們應用於下一個字節(對它應用完全相同的過程之后)

暫無
暫無

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

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