• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            asm, c, c++ are my all
            -- Core In Computer
            posts - 139,  comments - 123,  trackbacks - 0

            [轉]AT&T x86 asm 語法

            創建時間:2001-04-09
            文章屬性:翻譯

            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 <libc/asmdefs.h>

            ??? .file "myasm.S"

            ??? .data
            ??? .align 2
            ??? somedata: .word? 0
            ??? ...

            ??? .text
            ??? .align 4
            ??? FUNC(__MyExternalAsmFunc)
            ??? ENTER
            ??????????? movl?? ARG1, %eax
            ??????????? ...
            ??????????? jmp??? mylabel
            ??????????? ...
            ??????? mylabel:
            ??????????? ...
            ??? LEAVE
            這是一個好的純粹的匯編代碼框架

            posted on 2006-04-23 17:53 Jerry Cat 閱讀(575) 評論(0)  編輯 收藏 引用

            <2006年7月>
            2526272829301
            2345678
            9101112131415
            16171819202122
            23242526272829
            303112345

            常用鏈接

            留言簿(7)

            隨筆檔案

            最新隨筆

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜

            亚洲国产精品婷婷久久| 久久人人爽人人爽人人片AV高清 | 奇米综合四色77777久久| 欧美午夜A∨大片久久| 亚洲欧洲久久av| 国内精品久久久久影院亚洲| 久久综合色老色| 久久精品青青草原伊人| 久久亚洲AV无码精品色午夜| 久久久久久国产精品美女 | 久久精品国产69国产精品亚洲| www.久久热.com| 国产免费久久久久久无码| 欧洲国产伦久久久久久久| 久久综合色老色| 精品久久久久久无码专区| 99精品久久久久久久婷婷| 无码人妻久久一区二区三区蜜桃| 一本久久a久久精品综合香蕉| 亚洲精品乱码久久久久久久久久久久| 国产亚洲欧美精品久久久| 伊人热人久久中文字幕| 亚洲午夜精品久久久久久app| 久久久久高潮综合影院| 精品久久久久久国产91| 狠狠色丁香婷婷久久综合五月 | 久久精品国产日本波多野结衣| 精品久久久久久国产潘金莲| 久久精品18| 久久九九精品99国产精品| 久久久久亚洲AV综合波多野结衣| 99久久国产综合精品女同图片| 国产精品久久久天天影视香蕉| 久久AV高潮AV无码AV| 99精品久久久久久久婷婷| 色欲综合久久中文字幕网| 亚洲国产精品久久| 丰满少妇人妻久久久久久| 日本WV一本一道久久香蕉| 国产精品热久久毛片| 国产精品美女久久久m|