http://firstdot.spaces.live.com/
1.gcc嵌入彙編
(1). 在gcc嵌入彙編中輸入輸出使用相同的寄存器?
static void * __memcpy(void * to, const void * from, size_t n)
{
int d0,d1,d2;
__asm__ __volatile__(
"rep;movsl/n/t"
"testb $2,%b4/n/t"
"je 1f/n/t"
"movsw/n"
"1:/ttestb $1,%b4/n/t"
"je 2f/n/t"
"movsb/n"
"2:"
:"=&c" (d0), "=&D" (d1), "=&S" (d2)
:"0" (n/4), "q" (n), "1" ((long) to), "2" ((long) from)
:"memory");
return (to);
}
運算元0,1,2和3,5,6使用相同的寄存器的理解:
a. 3,5,6在輸入過程中將值n/4,to和from的地址讀入ecx,edi,esi寄存器中;
b. 0,1,2在輸出過程中將ecx,edi,esi寄存器中的值存入d0,d1,d2記憶體變數中。
c. 注意在上面的語句中也有"&"限定符,但輸入和輸出仍使用相同的寄存器,如運算元0和3都使用寄存器ecx,這是因為"0"限定的結果,如果
把"0" (n/4)換成"c" (n/4),則因為"=&c"的限定而使得編譯時間報錯。
(2). 關於gcc嵌入式彙編中"&"限定符的作用?
"&"限定符用於輸出運算元,使其唯一的使用某寄存器
int bar,foo;
__asm__ __volatile__(
"call func /n/t"
"mov ebx,%1"
:"=a" (foo)
:"r" (bar));
在gcc編譯時間預設會讓bar也使用eax寄存器,如果把"=a"改為"=&a",那麼foo將唯一使用eax,而讓bar使用其它的寄存器。
(3). _start和main的關係?
main是gcc看到的程式進入點,而ld和as所看到的程式進入點其實是_start。libc庫中的_start會調用main函數。
a. 編譯帶_start的組譯工具時的步驟:as -o a.o a.s,ld -o a a.o; gcc -g -c a.s,ld -o a a.o。(使用gcc編譯可以增加調試選項-g,這
時不能直接用gcc -o a a.s編譯的原因是gcc會預設在程式中尋找main函數,並且會將libc中的_start加入進來。如果直接用gcc -o a a.s編譯
,則會報兩個錯誤"重複的_start"和"沒找到main")
b. 編譯帶main的組譯工具或C程式時的步驟:gcc -o a a.s;gcc -o a a.c。
(4).section和.previous
將這兩個.section和.previous中間的代碼彙編到各自訂的段中,然後跳回去,將這之後的的代碼彙編到上一個section中(一般是.text段),
也就是自訂段之前的段。.section和.previous必須配套使用。
2. AT&T彙編
(1).data,.section等都是偽操作,不能直接翻譯成機器碼,只有相應的assembler才能識別
(2).section將程式分成幾個片斷,如.data,.text,.bss
(3).globl 函數名表示該函數被export,並可以被其它檔案中的函數調用
(4).bss可以用來申請一塊空間,但不需要對其進行初始化
(5)使用核心定義函數如open,read等可以通過int $80中斷來完成
(6)MOVL $FOO,%EAX是把FOO在記憶體中的地址放到EAX中,而MOVL FOO,%EAX是把FOO這個變數的內容放入EAX
(7).include "檔案名稱",將其它檔案包含進來
(8)如何在彙編中表示結構?如c語言中的如下結構:
struct para
{
char Firstname[40];
char Lastname[40];
char Address[240];
long Age;//4 bytes
}
在彙編中可以表示成:
.section data
record1:
.ascii "Fredrick/0"
.rept 31 #Padding to 40 bytes
.byte 0
.endr
.ascii "Bartlett/0"
.rept 31 #Padding to 40 bytes
.byte 0
.endr
.ascii "4242 S Prairie/nTulsa, OK 55555/0"
.rept 209 #Padding to 240 bytes
.byte 0
.endr
.long 45
其中.rept n和.endr表示重複兩者之間的序列n次,可用於填充資料
(9)當組譯工具由多個檔案構成時,可以採用以下方式編譯與串連:
as write-records.s -o write-records.o (gcc -g -c write-records.s)
as write-record.s -o write-record.o (gcc -g -c write-record.s)
ld write-record.o write-records.o -o write-records
(10)如何在組合語言中使用動態庫中的函數?
#helloworld-lib.s
.section .data
helloworld:
.ascii "hello world/n/0"
.section .text
.globl _start
_start:
pushl $helloworld
call printf
pushl $0
call exit
as helloworld-lib.s -o helloworld-lib.o
ld -dynamic-linker /lib/ld-linux.so.2 -o helloworld-lib helloworld-lib.o -lc
產生動態庫:ld -shared write-record.o read-record.o -o librecord.so
(11)使用彙編檔案產生動態庫
as write-record.s -o write-record.o
as read-record.s -o read-record.o
ld -shared write-record.o read-record.o -o librecord.so
as write-records.s -o write-records.o
ld -L . -dynamic-linker /lib/ld-linux.so.2 -o write-records -lrecord write-records.o
記得運行write-records時還需要將動態庫路徑加到/etc/ld.so.conf中,並運行ldconfig
(12)編譯彙編檔案時如何產生偵錯符號
as --gstabs a.s -0 a.o 或者gcc -g -c a.s
附錄:
(1)函數調用時棧的情況
#Parameter #N <--- N*4+4(%ebp)
#...
#Parameter 2 <--- 12(%ebp)
#Parameter 1 <--- 8(%ebp)
#Return Address <--- 4(%ebp)
#Old %ebp <--- (%ebp)
#Local Variable 1 <--- -4(%ebp)
#Local Variable 2 <--- -8(%ebp) and (%esp)
(2)例子
.include "external_func.s"
.section .data
data_array: #定義long型數組
.long 3,67,34,0
data_strings: #定義字串
.ascii "Hello there/0"
data_long: #定義long型變數
.long 5
.section .bss
.lcomm my_buffer, 500 #申請一塊500位元組的記憶體
.section .text
.equ LINUX_SYSCALL, 0x80 #定義符號LINUX_SYSCALL的值為0x80
.globl _start
_start:
pushl %edx
movl data_long,%edx #將data_long變數的值放入edx寄存器
movl $data_long,%edx #將data_long的地址放入edx寄存器
popl %edx
pushl $3 #push second argument
pushl $2 #push first argument
call power #call the function
addl $8, %esp #move the stack pointer back
pushl %eax #save the first answer before,calling the next function
movl $1, %eax #exit (%ebx is returned)
int $LINUX_SYSCALL
.type power, @function #定義函數power
power:
pushl %ebp #save old base pointer
movl %esp, %ebp #make stack pointer the base pointer
subl $4, %esp #get room for our local storage
movl 8(%ebp), %eax #put first argument in %eax
movl 12(%ebp), %ebx #put second argument in %ebx
imull %ebx,%eax
movl %ebp, %esp #restore the stack pointer
popl %ebp #restore the base pointer
ret