binutils是一些用來處理執行檔的額外程式,除了前面說過的組譯用的as ld, 另外有觀看執行檔的變數函式名稱(symbol)用的nm,剔除symbol的strip等等。 有用的程式
objdump :看OBJ檔的資訊 nm :看OBJ檔的symbol table。 strip :把symbol table還有debug stab拿掉,但這樣的OBJ檔無法用nm看出symbol, 也無法用gdb來除錯了。 strings :看string table,只是看這個檔裡面有什麼秀的出來的文字。 sting在ELF格式裡面用來代表symbol與section的名字。 ar :archive(靜態連結函數庫libxxx.a)的建造 ld :link editor 同時也是建造shared obj(libxxx.so)的建造。 |
int main(){return 0;} |
$ objdump -x a.out |
$ nm a.out |
$ strip a.out |
$ nm --dynamic /lib/libcxxxx.so |
Unix下寫組合語言, 這個需要組合語言的基礎也要有系統的觀念。 使用的工具有nasm或GNU as, nasm用Intel的語法就可以, GNU as跟其它unix上的工具as一樣要按照AT&T的語法規定, 所以如果你是先學Intel的有些語法上需要注意。
AT&T assembly與Intel/Microsoft syntax的不同
source在前面destination在後面
Intex Syntax AT&T Syntax instr dest,source instr source,dest mov eax,[ecx] movl (%ecx),%eax |
AT&T前面要加個%
Intel Syntax AT&T Syntax mov eax,1 movl $1,%eax mov ebx,0ffh movl $0xff,%ebx int 80h int $0x80 |
AT&T前面要加個$
Intel Syntax AT&T Syntax mov eax,1 movl $1,%eax mov ebx,0ffh movl $0xff,%ebx int 80h int $0x80 |
AT&T用大括號()
Intel Syntax AT&T Syntax instr foo,segreg:[base+index*scale+disp] instr %segreg:disp(base,index,scale),foo mov eax,[ebx+20h] movl 0x20(%ebx),%eax add eax,[ebx+ecx*2h] addl (%ebx,%ecx,0x2),%eax lea eax,[ebx+ecx] leal (%ebx,%ecx),%eax sub eax,[ebx+ecx*4h-20h] subl -0x20(%ebx,%ecx,0x4),%eax |
必需指定長度 根據系統而不一樣 word有的是32 bits有的是16 bits
b : byte w : word l : long Intel Syntax AT&T Syntax mov al,bl movb %bl,%al mov ax,bx movw %bx,%ax mov eax,ebx movl %ebx,%eax mov eax, dword ptr [ebx] movl (%ebx),%eax |
s (signed) z (zero) bl (from byte to long) bw (from byte to word) wl (from word to long) movsbl %al, %edx |
Intel Syntax AT&T Syntax jmp far seg:offsetljmp seg, offset jmp far INITSEG:GO ljmp $INITSEG, $GO call far INITSEG:GO lcall $INITSEG, $GO ret far STACK_ADJUS lret $STACK_ADJUST |
在C語言中勘進組語的程式碼加個__asm__("asm code");
__asm__("movl $1,%eax\n\t" // SYS_exit "xor %ebx,%ebx\n\t" "int $0x80" ); |
__asm__(asm statements : outputs : inputs : clobber); |
int main (void) { int operand1, operand2, sum, accumulator; operand1 = rand (); operand2 = rand (); __asm__ ("movl %1, %0\n\t" "addl %2, %0" : "=r" (sum) /* output operands */ : "r" (operand1), "r" (operand2) /* input operands */ : "0"); /* clobbered operands */ accumulator = sum; __asm__ ("addl %1, %0\n\t" "addl %2, %0" : "=r" (accumulator) : "0" (accumulator), "g" (operand1), "r" (operand2) : "0"); return accumulator; } |
r, g, 0這些東西叫constraints(限制的意思),每一個符號有特殊意義 代表這個暫存器必需是什麼型式的(暫存器有通用暫存器,符點運算暫存器, cpu指令有的允許直接對memory做運算,有的不準等等條件的暫存器, r代表通用型暫存器)。
output operand前一定要有個"="表示這個constraint是read-ony, "="叫constraint modifier。
input output operands後一定要跟著相對應的C 變數的參數, 這是給asm的參數。
如果statement裡真要指定register要多加個%變成%%eax
I, J, K .... P 是根據不同cpu可以做不同的解釋來表示一個範圍的立即定址整數 Q, R, S .... U 0, 1, 2 .... 相對於assembly statement裡的%0 %1 %2 .... a, b, c .... f 可以根據不同cpu可以做不同定義的registers m 表示這是一個memory的operand 例如mov eax, data中的data p 合法的記憶體位址 r 一般通用型register g 任何的通用型register, memory operand, 立即定址的整數 constraints在386上有 a eax b ebx c ecx d edx S esi D edi I 表示只有constant value (0 to 31)才行 r 可以是eax ebx ecx edx esi edi q 可以是eax ebx ecx edx g eax, ebx, ecx, edx or variable in memory A eax and edx combined into a 64-bit integer (use long longs) |
在C裡面有volatile這個宣告,通常是說這個變數會被外在routine改變, 在kernel裡面通常是指會被interrupt handler(有時就是硬體中斷的routine) 改變值,也就是被非同步的改變的變數。例如
unsigned long vloatile jiffies; |
在asm裡面是說這個東西compiler時,gcc不要雞婆作optimized,因為 最佳化的結果,compiler會把code按照他想的方法放到記憶體裡, 但是有的code我們需要特定指定他一定要在某個記憶體上, 在kernel裡常有這樣情形發生,我們可以用 __asm__ __volatile__宣告一段assembly的code是不要做最佳化的。 例如cli sti
#define disable() __asm__ __volatile__ ("cli"); #define enable() __asm__ __volatile__ ("sti"); |
在MASM裡有一些特殊的假指令,也就是真正的CPU裡沒有這些指令, 但MASM給了方便的假指令,例如
.DATA |
.byte expression expression送到下個byte的位置
.data subsection 告訴as下面的code要編在data section的尾巴裡 並且給一個編號subsection
.section name 告訴as下面的code要編在section裡 並給這個section一個名字
.text subsection 告訴as下面的code要編在text section的尾巴裡 並且給一個編號subsection
.word expression expression送到下個word
#define RDTSC(llptr) ({ \ __asm__ __volatile__ ( \ ".byte 0x0f; .byte 0x31" \ : "=A" (llptr) \ : /* no input operand */ : "%eax", "%edx"); }) |