先承認我自己很不滿意這篇,太亂了。只能當工具查keyword用。不過as 手冊的確就是指令和語法。原本是以英文字母順序說明,我只是把這些用自認的方式重新分類。很多地方也真的只有句意翻譯。就把他當作看手冊的導讀,有找的需要的再進去看手冊吧。
本篇只討論ELF部份,其他binary format跳過。
目錄
as參數
只提幾個我有興趣的部份
-Z:硬上,就算有錯誤照樣組譯沒有錯的部份。--gstabs+:好東西,可以幫你加入debug資訊,然後直接用gdb除錯。- 如果檔案副檔名為
.s,就是普通的組合語言原始檔。 - 如果檔案副檔名為
.S,就可以使用cpp(還記得c preporcessor吧?)來處理前置處理。
名詞解釋
symbol:由字母、數字、和_、.、$組成的字串。不得以數字開頭。label:symbol後面加:
.開頭的symbol是gas 的directiveexpression:運算式,結果代表不是位址就是單純的數字- 原始碼不是以上的情況,由英文字母開頭組成的字串就是instruction
- 原始碼最後一行一定要是
\n。目前網友Carl有提供為什麼這樣規定的link。
常數
- 字元常數:
'字元- 顯示\:
'\\
- 字串:
"字串"
Section
一個連續的記憶體空間。這段連續空間都是為了處理某些單一特定的任務如執行程式碼、存放global變數等。
題外話,.bss存在的目的是節省儲存空間,沒有初始的全域變數當然不需要在檔案中保留儲存空間。
undefined section
在組譯的時段只要位址無法決定的symbol,一律放到undefined section。然後祈禱linker幫你搞定。
relocation
前面的文有提到,linker功能之一就是把不同的object檔案黏成一個執行檔。要怎麼黏呢?
每個object 檔案的起始點都是address 0。由linker計算並設定每個object檔案最後在執行檔放置的address,避免這些object的內容互相覆蓋。
而linker要怎麼搬移和設定最後的位址呢?這是因為object檔案內已經有規範好的不同名稱的好幾個連續空間,也就是section。所以linker把這些object檔案中相同section名稱的連續空間搬到執行檔內相同名稱的空間,並且保證執行檔內這些section的空間也是連續的。而搬移的動作並設定section的runtime address就稱為relocation。
Linker在relocation時需要考慮的問題,as也幫他處理了,這些問題是
- 目前這個位址要對應到object檔案的哪個地方?
- 這個位址會需要佔用多少byte的空間?不懂?int和char吃的空間總會不一樣吧。
- 目前位址對應到的是哪個section? 這個位址和對應section的offset為何?
- 目前的位址是絕對位址還是和program counter相對的位址?
另外要注意的是,大部分的位址可以表示成
1
| |
Expression
expression的結果代表不是位址就是單純的數字。這些數字要嘛是絕對位址、要嘛就是某個section的offset。而expression之間可以有空白。
Empty expression
空白字元或是null,其值會被設為0
Integer expression
由一個以上的argument和operator組成的expression
Arguments
包含 symbols, numbers 或subexpressions,分別討論
- symbol:結果將會是 {section setction的offset數值},數值會是32位元的二的補數(就是有正負值啦)
- numbers:一般來說,是正整數。如果你要處理浮點數或是大數(超過32位元的數字)as會噴警告。你需要自己處理這種情況。
- subexpressions:指的是
- (expression)
- prefix operator 伴隨一個 argument
Operators
用來協助運算section中的offset位址。
- Infix Operators
- 就一般的binary operator如
+,-等
- 就一般的binary operator如
- Prefix Operators
-:負號~:補數,就是將argument的每個位元inverse
Infix也和C語言一樣,有優先順序、符號定義也大致相同,列出如下
- 最優先
*,/,>>,<<
- 第二順位
|,&,^,!
- 第三順位
+,-,==,<>,!=,>,<,>=,<=<>就是!=
- 最低順位
&&,||
directives
重頭戲。directive又稱pseudo-ops,一律以.開頭。照字面理解,這東西是用來協助使用開發,而不是真正的CPU instruction。這邊我只列出看得懂我感興趣的部份。有興趣請參考出處。另外和硬體相依的directive請參考這邊。
變數相關
.ascii "字串":可以用多個字串,中間以,隔開。這些字串最終會被一起放在連續的記憶體中。.asciz "字串":和樓上的差別是字串後面會自動填\0,和C語言的字串表示方式相同。.balign[wl] abs-expr, abs-expr, abs-expr:和.align差別在b是byte,w是2-byte,l是4-byte。這代表什麼呢?代表要pad的數字(如果有指定的話)要注意fill byte數量。如.balignw 8, 0xbeef。.byte expressions:expression數量可以從0個到多個,中間以,隔開。這些expression會依照順序排列。那麼要幹什麼用呢?你可以這樣玩。
1
| |
.int expressions.long expressions- 上面兩個有同樣效果,
expression為16-bit寬度。可以用,隔開。和.byte用法類似。長度以及order會和CPU架構相關。
- 上面兩個有同樣效果,
.hword expressions.short expressions- 上面兩個有同樣效果,
expression為16-bit寬度。可以用,隔開。和.byte用法類似。
- 上面兩個有同樣效果,
.double flonums:就浮點數,可以用,隔開。和.byte用法類似。表示方式要看target CPU架構。.float flonums:就浮點數,可以用,隔開。和.byte用法類似。表示方式要看target CPU架構。.lcomm symbol, length:為symbol保留length的空間,該symbol型態不會是global,並且會被放在.bsssection。.octa 大數字:為16-byte寬度。可以用,隔開。和.byte用法類似。.quad 大數字:為8-byte寬度。可以用,隔開。和.byte用法類似。.string "字串":將字串放到object file中,看不出來和.ascii差在那。.string16 "字串":將字串放到object file中,字串中的單個字元將會展開成2個bytes。看不出來和.ascii差在那。.string32 "字串":將字串放到object file中,字串中的單個字元將會展開成4個bytes。看不出來和.ascii差在那。.string64 "字串":將字串放到object file中,字串中的單個字元將會展開成8個bytes。看不出來和.ascii差在那。.set symbol, expression:將symbol的值設成expression的值。.size symbol, expression:設定symbol空間為expression的值。
Symbol的描述
visibility:local, global or weak
.extern:單純是相容性使用,特地列出來只是因為手冊說as將所有undefined symbols視為extern.global symbol.globl symbol- 以上兩個同樣效果,就是讓
linker看得到這個symbol,也就是說透過nm觀察binary也可以看得到這些symbol。
- 以上兩個同樣效果,就是讓
.local symbol:讓linker看不到這個symbol。手冊上另外有提到.local不支援alignment的問題和解法。我看不懂,有興趣自行去連結參考。.weak symbol:組譯器找不到symbol會產生一個。
Symbol type
.type symbol, type:type 描述方式有五種。我只用我看順眼的那種說明。"function":這個symbol是個function"object":這個symbol用來存放資料"tls_object":這個symbol用來存放thread local資料"notype":沒有指定"gnu_unique_object":保證該symbol是唯一的symbol"gnu_indirect_function":看不懂
其他Symbol 相關
.desc symbol, abs-expression:提供描述symbol的特性,細節請參考前面的說明。.equ symbol, expression:將symbol設成expression的值.equiv symbol, expression:和上面類似,但是如果該symbol之前已經定義過,就會噴錯誤。
Section
.data:不解釋.test:不解釋.section name:讓as把以下的東西組成name的section。名字雖然可以亂取,但是也要看binary format有沒有支援。如a.out就沒有這東西。
ELF 下的Section directive
ELF的話,這個directive有加料。說明如下: []表示optional
.section name [, "flags"[, @type[,flag_specific_arguments]]]flags:可由下面的flag合體組成a:allocatable,就是要在記憶體內吃空間,但是loader不一定會載入東西到該sectione:非executable或是shared library的sectionw:可寫入x:可執行M:可被mergeS:該section有 zero terminated 字串G:屬於某個section groupT:給thread local存放東西用 (存放三小?)?:看不懂,跳過
type
由於@在某些平台如ARM上是註解的符號,這種情況需要用%替代。
G和M有特別規範,必須隔離在雙引號外面。而同時要用這兩個flag要以MG順序擺放,範例如下:
.section name , "flags"MG,...
Section group目前先假裝沒看到,有機會又看到再回來討論。
條件以及控制相關
- if 部份有點雜亂,懶得想範例測試,想像成C語言的
#ifdef。剩下自己看手冊。 .irp symbol,values...:和巨集概念很類似,把.irp ...到.endr之間的instruction用到symbol的部份全部換成value。範例如下。
.irp item, 2, 3, 4 mov %r\item, $\item .endr
會展開成
1 2 3 | |
.irpc symbol,values...:手冊上面的說明幾乎和irp相同,悲劇的是範例和.irp完全一致。唯一差別是.iprc中有提到character,只能猜測c是character。.offset loc:將locale counter設定成loc。.org new-lc, fill:同樣是更動locale counter,但是只能在同一個section中移動。另外一個要注意的是這個指令只能增加locale counter,硬要減少是不可能的。當locale couter移動後,中間的空白會填入fill的值。不加上, fillas會填0。.rept 次數:重複.rept到.endr指定的次數。.skip size, fill:產生size長度,fill值的資料。.fill repeat, size, value:產生value,佔用空間為size。是否要產生多個,否的話repeat填0,是的話repeat填要產生的個數。size和value為optional,size預設為1,value預設為0。.fill 2,,.fill 2,,10.fill 2,4,
.warning "string":印出警告訊息。.err:噴錯誤,除非as有-Z指令,不然別想產生obj檔。.error "錯誤訊息":印出錯誤訊息然後GG。不帶錯誤訊息as會印出檔案名稱和用了.error那行。.fail expression:expression值大於五百噴警告,小於五百噴錯誤。用在複雜的巢狀巨集或是條件式組合語言中。.print "字串":組譯的時候stdout會印出字串。.end:表示組合語言程式結束
巨集
跳過,自行看手冊
ELF相關
.symver symbol, symbol2@nodename:指定symbol的版本號碼,一般用在shared library中。詳細說明懶得看,那天GG再回來看。
ELF section stack
.subsection name:把目前的section push到section stack中,並且把目前的subsection置換成name。.popsection:從section stack中pop最上面的section去覆蓋目前的section.pushsection name [, subsection] [, "flags"[, @type[,arguments]]]:把目前的section push到section stack中,並且把目前的section置換成name以及subsection,type和argument和.section的參數相同。
ELF visibility
.protected symbol:不但外部看不到該symbol,連內部要使用讀取該symbol的另外一個symbol也要在內部定義。直接舉個虛擬C語言。
1 2 3 4 5 | |
.hidden symbol:想像C語言在function前面加上static,觀念類似,讓該symbol無法被其他component看見。手冊這樣的symbol通常被視為.protect symbol,目前懶得寫程式測試。單純猜測這兩個有不同,不然幹嘛要分成兩個指令。.internal symbol:手冊上提到除了和.hidden有同樣效果外,不同的CPU會針對這個symbol做特別處理,到底是哪些特別處理,手冊沒說。
除錯相關
大部分跳過,太多背景需要補完。
.def.endef.dim:給compiler產生除錯用。.file 檔案行號 檔名:DWARF2用的除錯,除錯時對應的原始碼行號。.func name[,label]:只有開啟除錯有效,必須在結尾加入.endfunc。label就是組合語言內的label,也就是該function的進入點。不填的話,就在name加上prefix 字元當作進入點,通常prefix字元為_。.loc fileno lineno [column] [options]:DWARF2用的除錯。整理如下- 手冊假設我們很瞭debug內部資訊,但是我不會。看下來他們有提到
.debug_line狀態機.debug_lineline number matrix- 不明暫存器:
is_stmtregister,isaregister等
- 手冊假設我們很瞭debug內部資訊,但是我不會。看下來他們有提到
- 資訊放在binary 的
.debug_linesection。 - 在debuger(?)載入
.debug_line資訊時,讀到該行,會把參數fileno,lineno,等參數一併載入。 - options:
basic_block:設定.debug_line狀態為basic_blockprologue_end:設定.debug_line狀態為prologue_endepilogue_begin:設定.debug_line狀態為epilogue_beginis_stmt value:設定is_stmtregister 在.debug_line狀態為value,合法數值只有0或1。isa value:設定isaregister 在.debug_line狀態為value,合法數值只有0或1。discriminator value:設定discriminatorregister 在.debug_line狀態為value,合法數值只有0或1。
.loc_mark_labels enable:是否enble,basic_block register,細節完全看不懂。只知道和debug line number entry有關。.stabs symbol, type, other, desc, value:用來提供資訊給symbolic debuger。詳細資訊請看手冊.tag structname:compiler產生的輔助directive。用來從symbol table中找出structname的instance。.val addr:看不懂。自己看手冊。看起來是紀錄addr的值,但是怎麼會和symbol table扯上關係??未分類
.include "file":從目前的位置,把file全部原封不動地放到之後的位置。.align abs-expr1, abs-expr2, abs-expr3:local counter(請參考前面linker script文)結束要對齊的位址倍數。abs-expr1:必填。要對齊的數字。根據CPU,數字代表可能是byte,有些代表的是bit。所以要對齊8有的CPU要填8,有些CPU要填3。心理的OS,欠揍。abs-expr2:optional。如果需要填空,可以指定填入的數值。不填就使用預設值,0。abs-expr3:optional。指定跳過數字最多可以幾個,超過就直接不對齊了。(手冊用skip而不用pad讓我在想這到底差別在那?)
如果後面兩個都不想填,可以直接下.align abs-expr1,,收工。
.comm symbol, length:我是這樣理解啦,就是很多C語言檔案要用同一個全域變數。先摸到的先贏。可以看我以前整理的說明。另外有兩點要注意- 如果有同樣的symbol,在不同檔案中,設定的長度又不同,gas會選最大的。
- ELF有隱藏的第3參數,用來指定alignment。
.gnu_attribute tag, value:GNU屬性自己查.ident 字串:不同binary format有不同處理,在ELF中會把字串放到.commentsection中。要注意,file包括command line參數中-I指定的路徑。.incbin "file"[,skip[,count]]:從目前的位置,把file原封不動地放到之後的位置。你可以透過skip指定從檔案起始地幾個byte後跳過。另外你也可以透過count指定檔案最多include幾個bytes。
另外一點要注意,file包括command line參數中-I指定的路徑。
.version "string":產生.notesection並且將字串放入該section。