簡體   English   中英

難以理解gcc的匯編輸出

[英]Trouble understanding gcc's assembly output

在編寫一些C代碼時,我決定將其編譯為匯編文件並進行讀取-我只是做些這樣的工作,時不時地這樣做-是一種練習,使我每次編寫代碼時都在思考機器在做什么用C語言聲明

無論如何,我用C編寫了這兩行

asm(";move old_string[i] to new_string[x]");
new_string[x] = old_string[i];
asm(";shift old_string[i+1] into new_string[x]");
new_string[x] |= old_string[i + 1] << 8;

old_stringchar的數組,而new_stringunsigned short的數組,因此給定兩個char,42和43,這會將4342放入new_string[x]
產生了以下輸出:

#move old_string[i] to new_string[x]

movl    -20(%ebp), %esi         #put address of first char of old_string in esi
movsbw  (%edi,%esi),%dx         #put first char into dx
movw    %dx, (%ecx,%ebx,2)      #put first char into new_string

#shift old_string[i+1] into new_string[x]

movsbl  1(%esi,%edi),%eax       #put old_string[i+1] into eax
sall    $8, %eax                #shift it left by 8 bits
orl     %edx, %eax              #or edx into it
movw    %ax, (%ecx,%ebx,2)      #?

(我自己發表評論,所以我可以關注發生的事情)。 我使用-O3進行了編譯,因此我還可以了解編譯器如何優化某些構造。 無論如何,我敢肯定這可能很簡單,但這是我沒有得到的:

第一部分從old_string[i]復制一個char ,然后將其從(從dx )移動到(%ecx,%ebx) 然后在下一節中,復制old_string[i+1] ,將其移位或old_string[i+1] ,然后將其從ax放到同一位置。 它將兩個16位值放在同一位置? 這不行嗎?

同樣,它將old_string[i+1]移至eax的高階雙字,然后將edxnew_string[x] )放入其中……然后將ax放入內存! ax不只是包含new_string[x]已經存在的new_string[x]嗎? 這樣可以將同一事物兩次保存到內存中的同一位置?

有什么我想念的嗎? 另外,我相當確定編譯程序的其余部分與該代碼段無關...我在前后閱讀了一下,以查找每個數組和不同變量的存儲位置以及寄存器的值將在到達該代碼時-我認為這是匯編的唯一一部分,對這些C行很重要。

-哦,原來GNU匯編注釋以#開頭。

好的,畢竟這很簡單。 我用筆和紙弄清楚了,寫下了每個步驟,對每個寄存器做了什么,然后寫下一個初始起始值,記下了每個寄存器的內容...

讓我感到驚訝的是,它正在將32位和16位寄存器用於16和8位數據類型...這是我想發生的事情:

  • 內存中的第一個值是0001(我在想01)。
  • 第二個值(02)加載到32位寄存器中(所以就像00000002,我在想的是0002)
  • 第二個值向左移8位(00000200,我在想,0200)
  • 第一個值(0000001,我以為0001)異或為第二個值(00000201,我以為0201)
  • 16位寄存器存入內存(0201,我當時在想,只是01)。

我不知道為什么將它兩次寫入內存,或者為什么它使用32位寄存器(嗯,實際上,我的猜測是32位處理器處理32位值的速度比8和12快得多。 16位值,但這完全是沒有根據的猜測),所以我嘗試重寫它:

movl -20(%ebp), %esi       #gets pointer to old_string
movsbw (%edi,%esi),%dx     #old_string[i] -> dx (0001)
movsbw 1(%edi,%esi),%ax    #old_string[i + 1] -> ax (0002)
salw $8, %ax               #shift ax left (0200)
orw %dx, %ax               #or dx into ax (0201)
movw %ax,(%ecx,%ebx,2)     #doesn't write to memory until end

這完全一樣。

我不知道這是否是一種優化(除了將一個內存寫出來,這顯然是),但是如果是這樣,我知道這不是很值得,也沒有給我帶來任何好處。 無論如何,我都知道這段代碼現在正在做什么,感謝大家的幫助。

我不確定不知道什么,除非我錯過了一些東西。

前3條指令將old_string中的一個字節加載到dx中,並將其存儲到new_string中。

接下來的3條指令利用dx中已有的內容,並將old_string [i + 1]與dx合並,並將其作為16位值(ax)存儲到new_string。

同樣,它將old_string [i + 1]移至eax的高階雙字,然后將edx(new_string [x])放入其中……然后將ax放入內存! 斧頭不只是包含new_string [x]中已經存在的東西嗎? 這樣可以將同一事物兩次保存到內存中的同一位置?

現在您了解了為什么優化程序是一件好事。 這種冗余代碼經常出現在未優化的生成代碼中,因為生成的代碼或多或少地來自不“知道”之前或之后發生的事情的模板。

暫無
暫無

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

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