《電子技術應用》
您所在的位置:首頁 > 嵌入式技術 > 解決方案 > AT&T x86 asm語法

AT&T x86 asm語法

2017-07-23
關鍵詞: 匯編語言

DJGPP 使用AT&T格式的匯編語法。和一般的intel格式的語法有點不同。主要不同點如下:

AT&T 語法顛倒了源和目的操作數的位置, 目的操作數在源操作數之后。寄存器操作數要有個%的前綴, 立即數操作數要有個$符號的前綴。 存儲器操作數的大小取決于操作碼的最后一個字符。 它們是b (8-bit), w (16-bit), 和 l (32-bit).

這里有一些例子。 左邊部分是intel指令格式,右邊是at&t格式。

movw %bx, %ax // mov ax, bx
xorl %eax, %eax // xor eax, eax
movw $1, %ax // mov ax,1
moVB X, %ah // mov ah, byte ptr X
movw X, %ax // mov ax, word ptr X
movl X, %eax // mov eax, X

大部分操作指令,at%t和intel都是差不多的,除了這些:

movsSD // movsx
movzSD // movz

S和D分辨代表源和目的操作數后綴。

movswl %ax, %ecx // movsx ecx, ax
cbtw // cbw
cwtl // cwde
cwtd // cwd
cltd // cdq
lcall $S,$O // call far S:O
ljmp $S,$O // jump far S:O
lret $V // ret far V

操作嘛前綴不能與他們作用的指令寫在同一行。 例如, rep 和stosd應該是兩個相互獨立的指令, 存儲器的情況也有一點不同。通常intel格式的如下:

section:[base + index*scale + disp]

被寫成:

section:disp(base, index, scale)

這里有些例子:

movl 4(%ebp), %eax // mov eax, [ebp+4])
addl (%eax,%eax,4), %ecx // add ecx, [eax + eax*4])
movb $4, %fs:(%eax) // mov fs:eax, 4)
movl _array(,%eax,4), %eax // mov eax, [4*eax + array])
movw _array(%ebx,%eax,4), %cx // mov cx, [ebx + 4*eax + array])

Jump 指令通常是個短跳轉。 可是, 下面這些指令都是只能在一個字節的范圍內跳轉: jcxz, jecxz, loop, loopz, loope, loopnz 和loopne。象在線文檔所說的那樣,一個jcxz foo可以擴展成以下工作:

jcxz cx_zero
jmp cx_nonzero
cx_zero:
jmp foo
cx_nonzero:

文檔也注意到了mul和imul指令。 擴展的乘法指令只用一個操作數,例如, imul $ebx, $ebx將不會把結果放入edx:eax。使用imul %ebx中的單操作數來獲得擴展結果。

Inline Asm

我將首先開始inline asm, 因為似乎關于這方面的疑問非常多。這是最基本的語法了, 就象在線幫助信息中描述的:

__asm__(asm statements : outputs : inputs : reGISters-modified);

這四個字段的含義是:

asm statements - AT&T 的結構, 每新行都是分開的。
outputs - 修飾符一定要用引號引起來, 用逗號分隔
inputs - 修飾符一定要用引號引起來, 用逗號分隔
registers-modified - 名字用逗號分隔
一個小小的例子:
__asm__("
pushl %eax\n
movl $1, %eax\n
popl %eax"
);

假如你不用到特別的輸入輸出變量或者修改任何寄存器的值,一般來說是不會使用到其他的三個字段的,

讓我們來分析一下輸入變量。

int i = 0;
__asm__("
pushl %%eax\n
movl %0, %%eax\n
addl $1, %%eax\n
movl %%eax, %0\n
popl %%eax"
:
: "g" (i)
); // increment i

不要為上面的代碼所困擾! 我將盡力來解釋它。我們想讓輸入變量i加1,我們沒有任何輸出變量, 也沒有改變寄存器值(我們保存了eax值)。 因此,第二個和最后一個字段是空的。 因為指定了輸入字段, 我們仍需要保留一個空的輸出字段, 但是沒有最后一個字段, 因為它沒被使用。在兩個空冒號之間留下一個新行或者至少一個空格。

下面讓我們來看看輸入字段。 附加描述符可以修正指令來讓你給定的編譯器來正確處理這些變量。他們一般被附上雙引號。 那么這個"g"是用來做什么的呢? 只要是合法的匯編指令,"g"就讓編譯器決定該在哪里加載i的值。一般來說,你的大部分輸入變量都可以被賦予"g", 讓編譯器決定如何去加載它們 (gcc甚至可以優化它們!)。 其他描述符使用"r" (加載到任何可用的寄存器去), "a" (ax/eax), "b" (bx/ebx), "c" (cx/ecx), "d" (dx/edx), "D" (di/edi), "S" (si/esi), 等等。

我們將要提到一個在asm代碼里面的如%0的輸入變量。如果我們有兩個輸入, 他們會一個是%0一個是%1, 在輸入段里按順序排列 (如下一個例子)。假如N個輸入變量且沒有輸出變量, 從%0 到%N-1將和輸入字段里的變量相對應, 按順序排列。

如果任何的輸入, 輸出, 寄存器修改字段被使用, 匯編代碼里的寄存器名必須用兩個%來代替一個%。對應于第一個沒有使用最后三個字段的例子。

讓我們看看兩個輸入變量且引入了"volatile"的例子:

int i=0, j=1;
__asm__ __volatile__("
pushl %%eax\n
movl %0, %%eax\n
addl %1, %%eax\n
movl %%eax, %0\n
popl %%eax"
:
: "g" (i), "g" (j)
); // increment i by j

Okay, 現在我們已經有了兩個輸入變量了。沒問題了, 我們只需要記住%0對應第一個輸入變量(在這個例子中是i), %1對應在i后面的列出的j。

Oh yeah, 這個volatile到底是什么意思呢? 它防止你的編譯器修改你的匯編代碼,就是不進行優化(紀錄, 刪除, 結合,等等優化手段。), 不改變代碼原樣來匯編它們。建議一般情況下使用volatile選項。

讓我們來看看輸出字段:

int i=0;
__asm__ __volatile__("
pushl %%eax\n
movl $1, %%eax\n
movl %%eax, %0\n
popl %%eax"
: "=g" (i)
); // assign 1 to i

這看起來非常象我們前面提到的輸入字段的例子; 確實也沒有很大的不同。所有的輸出修飾符前面都應該加上=字符,他們同樣在匯編代碼里面用%0到%N-1來表示, 在輸出字段按順序排列。你一定會問如果同時有輸入和輸出字段會怎么排序的呢? 好,下面一個例子就是讓大家知道如何同時處理輸入輸出字段的。

int i=0, j=1, k=0;
__asm__ __volatile__("
pushl %%eax\n
movl %1, %%eax\n
addl %2, %%eax\n
movl %%eax, %0\n
popl %%eax"
: "=g" (k)
: "g" (i), "g" (j)
); // k = i + j

Okay, 唯一個不清楚的地方就是匯編代碼中的變量的個數。我馬上來解釋一下。

當同時使用輸入字段和輸出字段的時候:

%0 ... %K 是輸出變量

%K+1 ... %N 是輸入變量

在我們的例子中, %0 對應k, %1 對應i, %2對應j。很簡單,是吧?

到現在為止我們都沒有使用最后一個字段(registers-modified)。如果我們要在我們的匯編代碼里使用任何寄存器, 我們要明確的用push和pop指令來保存它們, 或者列到最后一個字段里面讓gcc來處理它們。

這是前面的一個例子, 沒有明確的保留和存貯eax。

int i=0, j=1, k=0; __asm__ __volatile__("
pushl %%eax\n /*譯者注:好像原文說的有點問題,明明是保存了eax的值,:(*/
movl %1, %%eax\n
addl %2, %%eax\n
movl %%eax, %0\n
popl %%eax"
: "=g" (k)
: "g" (i), "g" (j)
: "ax", "memory"
); // k = i + j

我們讓gcc來保存和存貯eax, 如果必要的話。一個16-bit寄存器名代表了32-, 16-或8-bit寄存器。 如果我們要改寫內存 (寫入一個變量等。), 建議在register-modified字段里面來指定"memroy"修飾符。這意味著除了第一個例子我們都應該加上這個修飾符, 但是直到現在我才提出來, 是為了更簡單易懂。

在你的內聯匯編里面定位標號應該使用b或f來作為終止符, 尤其是向后向前的跳轉。(譯者注:b代表向后跳轉,f代表向前跳轉)

For example,
__asm__ __volatile__("
0:\n
...
jmp 0b\n
...
jmp 1f\n
...
1:\n
...
);

這里有個用c代碼和內聯匯編代碼混合寫的跳轉程序的例子(thanks to Srikanth B.R for this tip).

void MyFunction( int x, int y )
{
__asm__( "Start:" );
__asm__( ...do some comparison... );
__asm__( "jl Label_1" );
CallFunction( &x, &y );
__asm__("jmp Start");
Label_1:
return;
}
External Asm

Blah... Okay fine. Here's a clue: Get some of your C/C++ files, 且用gcc -S file.c來編譯。然后查看file.S文件。基本結構如下:

.file "myasm.S"
.data
somedata: .word 0
...
.text
.globl __myasmfunc
__myasmfunc:
...
ret

Macros, macros! 頭文件libc/asmdefs.h便于你寫asm。 在你的匯編代碼最前面包含此頭文件然后就可以使用宏了。一個例子: myasm.S:

#include
.file "myasm.S"
.data
.align 2
somedata: .word 0
...
.text
.align 4
FUNC(__MyExternalAsmFunc)
ENTER
movl ARG1, %eax
...
jmp mylabel
...
mylabel:
...
LEAVE

這是一個好的純粹的匯編代碼框架。


本站內容除特別聲明的原創文章之外,轉載內容只為傳遞更多信息,并不代表本網站贊同其觀點。轉載的所有的文章、圖片、音/視頻文件等資料的版權歸版權所有權人所有。本站采用的非本站原創文章及圖片等內容無法一一聯系確認版權者。如涉及作品內容、版權和其它問題,請及時通過電子郵件或電話通知我們,以便迅速采取適當措施,避免給雙方造成不必要的經濟損失。聯系電話:010-82306118;郵箱:aet@chinaaet.com。
亚洲一区二区欧美_亚洲丝袜一区_99re亚洲国产精品_日韩亚洲一区二区
欧美国产日韩一区二区| 国产精品久久久久免费a∨| 亚洲一区二区在线视频| 亚洲国产精品小视频| 欧美一级欧美一级在线播放| 亚洲私人影院在线观看| 一本色道久久综合亚洲精品按摩| 91久久夜色精品国产九色| 亚洲国产精品一区二区第一页 | 欧美日韩在线一区二区三区| 欧美精品自拍| 欧美精品在线观看91| 欧美www视频| 欧美h视频在线| 免费久久99精品国产自| 美日韩免费视频| 女生裸体视频一区二区三区| 欧美成人精品三级在线观看| 欧美激情在线有限公司| 欧美区在线播放| 欧美日在线观看| 亚洲国产精品传媒在线观看 | 亚洲一区影院| 亚洲欧美另类在线观看| 亚洲综合国产激情另类一区| 亚洲欧美日韩国产精品| 亚洲欧美在线x视频| 西西人体一区二区| 久久国产精品毛片| 亚洲人成小说网站色在线| 99精品欧美一区二区蜜桃免费| 日韩一级在线观看| 亚洲在线电影| 欧美专区第一页| 久久夜色精品国产欧美乱极品| 免费成人网www| 欧美日韩成人综合在线一区二区| 欧美三区美女| 国产婷婷精品| 亚洲国产欧美一区二区三区久久 | 国产一区二区三区高清| 亚洲国产成人porn| 一本色道久久综合精品竹菊 | 欧美三区在线视频| 国产免费成人av| 精品av久久707| 亚洲精品一区二区在线观看| 亚洲午夜一级| 亚洲国产精品黑人久久久| 一本到12不卡视频在线dvd | 久久久亚洲精品一区二区三区| 欧美福利电影网| 国产精品久久777777毛茸茸| 国产一区二区三区丝袜| 亚洲激情午夜| 亚洲综合清纯丝袜自拍| 亚洲国产一区二区视频| 亚洲线精品一区二区三区八戒| 久久国产夜色精品鲁鲁99| 欧美国产另类| 国产麻豆日韩| 亚洲日本视频| 欧美在线91| 亚洲视频导航| 久久亚洲美女| 国产精品青草久久| 在线国产亚洲欧美| 亚洲午夜久久久| 亚洲人成在线播放| 午夜精品久久久久久99热软件| 乱中年女人伦av一区二区| 国产精品久久看| 亚洲国产小视频在线观看| 午夜激情亚洲| 中日韩美女免费视频网站在线观看| 久久久精品999| 国产精品高清网站| 亚洲区欧美区| 亚洲福利视频在线| 欧美一级淫片aaaaaaa视频| 欧美日本不卡高清| 精品91在线| 性欧美1819sex性高清| 宅男精品导航| 欧美+日本+国产+在线a∨观看| 国产精品综合视频| 99在线精品观看| 亚洲日本欧美| 久久人人97超碰精品888| 国产精品毛片在线看| 亚洲精品综合久久中文字幕| 亚洲高清毛片| 久久久久国产精品厨房| 国产精品一区二区三区久久久 | 欧美成人国产| 激情六月婷婷综合| 欧美夜福利tv在线| 亚洲免费视频在线观看| 欧美另类人妖| 亚洲第一在线综合网站| 亚洲伊人一本大道中文字幕| 在线一区二区三区四区| 欧美精品 国产精品| 在线欧美一区| 亚洲国产婷婷| 久久综合综合久久综合| 国内精品嫩模av私拍在线观看| 午夜久久tv| 欧美一区二区播放| 国产精品久久久久久久久果冻传媒| 日韩午夜在线电影| 在线视频一区二区| 欧美精品在线一区二区| 91久久精品一区二区三区| 亚洲靠逼com| 欧美激情中文不卡| 最新国产成人av网站网址麻豆| 亚洲国产精品v| 久久美女性网| 娇妻被交换粗又大又硬视频欧美| 久久成人精品电影| 久久综合给合久久狠狠狠97色69| 韩国女主播一区| 亚洲高清中文字幕| 美女爽到呻吟久久久久| 亚洲第一中文字幕在线观看| 亚洲黄色在线观看| 欧美高清在线一区| 亚洲精品乱码久久久久久久久| 夜夜嗨一区二区| 国产精品theporn88| 亚洲在线免费视频| 久久精品国产999大香线蕉| 国产模特精品视频久久久久| 性一交一乱一区二区洋洋av| 久久久久久久精| 狠久久av成人天堂| 亚洲精品国产精品国自产观看浪潮| 欧美aa国产视频| 亚洲精品一区中文| 亚洲男同1069视频| 国产日韩亚洲欧美综合| 久久成人这里只有精品| 欧美成人伊人久久综合网| 亚洲免费av网站| 午夜一区二区三视频在线观看| 国产亚洲欧洲一区高清在线观看| 久久福利电影| 欧美精品一区二区蜜臀亚洲| 这里只有精品丝袜| 欧美在线免费看| 黄色一区二区三区四区| 亚洲精品免费网站| 欧美日韩一区二区三区免费| 亚洲一区二区三区四区视频| 久久精品中文字幕一区| 在线精品视频一区二区| 一区二区免费看| 国产日韩在线视频| 亚洲韩国精品一区| 欧美日韩一区二区在线观看| 亚洲欧美在线免费| 免费在线看成人av| 亚洲视频1区| 狼人天天伊人久久| 亚洲毛片在线免费观看| 欧美影院在线播放| 亚洲国产天堂久久综合| 午夜精品久久| 亚洲国产裸拍裸体视频在线观看乱了中文| 一区二区三区视频免费在线观看| 国产精品自拍三区| 91久久中文字幕| 国产精品久久久久久久久果冻传媒| 久久精品免视看| 欧美视频网址| 久久精品免费看| 国产精品v欧美精品v日本精品动漫| 欧美伊人久久大香线蕉综合69| 欧美精品激情在线观看| 亚洲自拍偷拍一区| 欧美久久久久| 久久精品91| 欧美性猛交99久久久久99按摩 | 国产精品久久久久久户外露出 | 一区二区电影免费观看| 老妇喷水一区二区三区| 亚洲性视频网址| 欧美黄网免费在线观看| 午夜精品福利在线| 欧美日韩一区二区国产| 亚洲福利精品| 国产免费成人| 亚洲一区二区三区影院| 亚洲国产精品久久久久久女王| 久久av红桃一区二区小说| 99re66热这里只有精品3直播| 久久综合久久综合久久综合| 亚洲免费影视| 欧美日韩一区二区欧美激情|