stol函数在linux下使用,Linux下ATT汇编语法简介一
這顯得很古怪,不過在gcc知道程序員拿這些寄存器做些什么后,這確實能夠對gcc的優化操作有所幫助。表5-3中是一些可能會用到的寄存器加載代碼及其具體的含義。
表5-3 常用寄存器加載代碼說明
代 碼
說 明
代 碼
說 明
a
使用寄存器eax
m
使用內存地址
b
使用寄存器ebx
o
使用內存地址并可以加偏移值
c
使用寄存器ecx
I
使用常數0~31
d
使用寄存器edx
J
使用常數0~62
S
使用esi
K
使用常數0~255
D
使用edi
L
使用常數0~65535
q
使用動態分配字節可尋址機寄存器(eax、ebx、ecx、或edx)
M
使用常數0~3
r
使用任意動態分配的寄存器
N
使用1字節常數
g
使用通用有效的地址即可(eax、ebx、ecx、edx或內存變量)
O
使用常數0~31
A
使用eax與edx聯合(64位)
下面的例子不是讓程序員自己指定哪個變量使用哪個寄存器,而是讓gcc為程序員選擇。
01?asm("leal (%1, %1, 4),
%0"02?: " =r"(y)03?: "0"(x));
第一句匯編語句leal(r1,r2,4),r3語句表示r1+r2*4→r3,。這個例子可以非常快地將x乘5。其中“%0”,“%1”是指gcc自動分配的寄存器。這里“%1”代表輸入值x要放入的寄存器,“%0”表示輸出值寄存器。輸出寄存器代碼前一定要加入等于號。如果輸入寄存器的代碼時0或為空時,則說明使用與相應輸出一樣的寄存器。所以。如果gcc將r指定為eax的話,那么上面匯編語句的含義即為:“leal(eax,eax,4),eax”。
注意:在執行代碼時,如果不希望匯編語句被gcc優化而改變位置,就需要在asm符號后面添加volatile關鍵詞:asm
volatile(……);
或者更詳細地說明為:_
_asm_ _ _ _volatile_ _(……);
一、AT&T 格式Linux 匯編語法格式
1.在 AT&T
匯編格式中,寄存器名要加上 '%' 作為前綴;而在 Intel 匯編格式中,寄存器名不需要加前綴。?AT&T
格式
Intel
格式
pushl �x
push eax
2.在 AT&T 匯編格式中,用 '$' 前綴表示一個立即操作數;而在 Intel
匯編格式中,立即數的表示不用帶任何前綴。例如:
AT&T
格式
Intel
格式
pushl $1
push 1
AT&T 和 Intel
格式中的源操作數和目標操作數的位置正好相反。在 Intel 匯編格式中,目標操作數在源操作數的左邊;而在
AT&T 匯編格式中,目標操作數在源操作數的右邊。例如:
AT&T
格式
Intel
格式
addl $1, �x
add eax, 1
在 AT&T
匯編格式中,操作數的字長由操作符的最后一個字母決定,后綴'b'、'w'、'l'分別表示操作數為字節(byte,8
比特)、字(word,16 比特)和長字(long,32比特);而在 Intel 匯編格式中,操作數的字長是用 "byte ptr"
和 "word ptr" 等前綴來表示的。例如:
AT&T
格式
Intel
格式
movb val, %al
mov al, byte ptr val
5.在 AT&T
匯編格式中,絕對轉移和調用指令(jump/call)的操作數前要加上'*'作為前綴,而在 Intel 格式中則不需要。
遠程轉移指令和遠程子調用指令的操作碼,在
AT&T 匯編格式中為 "ljump" 和 "lcall",而在 Intel 匯編格式中則為 "jmp
far" 和 "call far",即:
AT&T
格式
Intel
格式
ljump $section, $offset
jmp far section:offset
lcall $section, $offset
call far section:offset
與之相應的遠程返回指令則為:
AT&T
格式
Intel
格式
lret $stack_adjust
ret far stack_adjust
在 AT&T 匯編格式中,內存操作數的尋址方式是
section:disp(base, index, scale)
而在 Intel 匯編格式中,內存操作數的尋址方式為:
section:[base + index*scale + disp]
由于 Linux 工作在保護模式下,用的是 32
位線性地址,所以在計算地址時不用考慮段基址和偏移量,而是采用如下的地址計算方法:
disp + base + index * scale
下面是一些內存操作數的例子:
AT&T
格式
Intel
格式
movl -4(�p), �x
mov eax, [ebp - 4]
movl array(, �x, 4), �x
mov eax, [eax*4 + array]
movw array(�x, �x, 4), %cx
mov cx, [ebx + 4*eax + array]
movb $4, %fs:(�x)
mov fs:eax, 4
linux內核嵌入式匯編總結(1)
在linux內核中有很多的嵌入式匯編代碼。
嵌入匯編的基本格式為:
asm("匯編語句":輸出寄存器:輸入寄存器 :會被修改的寄存器);
其中”匯編語句”是程序員寫匯編指令的地方;”輸出寄存器”表示當這段嵌入式匯編執行之后,哪些寄存器用于存放輸出數據。這些寄存器會分別對應一個C語言表達式或一個內存地址;“輸入寄存器”表示在開始執行匯編代碼時,這里指定的一些寄存器中應存放的輸入值,它們也分別對應著一個C變量或常數值。下面用例子來說明嵌入式匯編語句的使用方法。
我們在下面列出了一段代碼作為例子來詳細解說,
01?#define get_seg_byte(seg,addr)
\?02?({
\?03?register char __res;
\?04?__asm__("push %%fs;
\?05?mov %%ax, %%fs;
\?06?movb %%fs: %2, %%al;
\?07?pop %%fs"
\?08?:" =a" (__res)
\?09?:"" (seg),"m" (* (addr)));
\?10?__res; })
這段10行代碼定義了一個嵌入式匯編語言宏函數。通常使用匯編語句最方便的方式是把它們放在一個宏內。用圓括號括住的組合語句(花括號中的語句)可以作為表達式使用,其中最后的變量__res(第10行)是該表達式的輸出值。
因為是宏語句,需要在一行上定義,因此這里使用反斜杠'\'將這些語句連成一行。這條宏定義將被替換到宏名稱在程序中被引用的地方。第1行定義了宏的名稱,也就是宏函數名稱get_seg_byte(seg,addr)。第3行定義了一個寄存器變量_
_res。第4行上的_ _asm_
_表示嵌入式語句的開始。從第4行到第7行的4條AT&T格式的匯編語句。?第8行是輸出寄存器,這句的含義是在這段代碼運行結束后將eax所代表的寄存器的值放入_
_res變量中,作為本函數的輸出值,“=a”中的“a”稱為加載代碼,“=”表示這是輸出寄存器。第9行表示在這段代碼開始運行時將seg放到eax寄存器中,“”表示使用與上面同個位置的輸出相同的寄存器。而(*(addr))表示一個內存偏移地址值。為了在上面匯編語句中使用該地址值,嵌入式匯編程序規定把輸入和輸出寄存器統一按順序編號,順序是從輸出寄存器序列從左到右從上到下以“%0”開始,分別記為%0、%1、……%9。因此,輸出寄存器的編號是%0(這里只有一個輸出寄存器),輸出寄存器前一部分(””(seg))的編號是%1,而后部分的編號是%2。上面第6行上的%2即代表(*(addr))這個內存偏移量。
現在我們來研究4~7行上的代碼的作用。第一句將fs段寄存器的內容入棧;第二句將eax中的段值賦給fs段寄存器;第三句是fs:(*(addr))所指定的字節放入al寄存器中。當執行完匯編語句后,輸出寄存器eax的值將被放入_
_res,作為該宏函數的返回值。
01?asm("cld\n\t"02?"rep\n\t"03?"stol"04?:
05?:
"c"(count-1), "a"(file_value),
"D"(dest)06?:
"�x", "�i");
1~3行這三句是通常的匯編語句,用以清方向位,重復保存值。第4行說明這段嵌入匯編程序沒有用到輸出寄存器。第5行的含義是:將count-1的值加載到ecx中,dest放到edi中。為什么要讓gcc編譯程序去做這樣的寄存器值的加載,而不讓我們自己做呢?因為gcc在它進行寄存器分配時可以進行某些優化工作。例如fill_value值可能已經在eax中。如果是在一個循環語句中的話,gcc就可能在整個循環操作中保留eax,這樣就可以在每次循環中少用一個movel語句。最后一行的作用是告訴gcc這些寄存器中的值已經改變了。
通過上面分析,我們知道,宏名稱中的seg代表一指定的內存段值,而addr表示一內存偏移地址量。到現在為止,我們應該很清楚這段程序的功能了吧!該宏函數的功能是從指定段和偏移值的內存地址處取一個字節。再看下一個例子。
總結
以上是生活随笔為你收集整理的stol函数在linux下使用,Linux下ATT汇编语法简介一的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 网站服务器商标属于哪类,网络水晶头属于商
- 下一篇: mysql_real_connect阻塞