AT&T組合語言——簡單一實例及工具示範

來源:互聯網
上載者:User

今天就來用具體執行個體代碼來運用一下昨天所說的只個工具的用法吧

這幾個執行個體主要的目的是來熟悉一下彙編相關工具的用法及應用一下昨天剛說的組譯工具模板。

 我們用到的工具主要有as,ld,gcc,gdb,當然,它們是運行在linux系統下的

廢話少說,直接來例子了。嗯,再說一句,下面的例子是參考或來自《組合語言程式設計》Richard Blum的

 

例一:列印出"hello,world!"

#hellowrold.s print "hello,world!".section .dataoutput:.ascii "hello,world\n".section .text.globl _start_start:movl $4, %eaxmovl $1, %ebxmovl $output,%ecxmovl $12,%edxint  $0x80movl $1, %eaxmovl $0, %ebxint  $0x80

簡單說一下代碼:

首先,在資料區段中聲明一個字串:

output:.ascii "hello,world\n"

.asscii聲明使用ASCII字元聲明一個文本字串。字串元素被預定義並且放在記憶體中,其起始記憶體位置由標籤output指示。

下面是聲明程式的指令碼段和一般的起始標籤,_start是連結器預設的起始程式碼:

.section .text.globl _start_start:
下面是直接調用write系統調用來顯示常值內容

        movl $4, %eaxmovl $1, %ebxmovl $output,%ecxmovl $12,%edxint  $0x80
Linux下write系統調用的參數:

EAX包含系統調用值,write是4

EBX包含要寫入的檔案描述符,我們知道,Linux終端中0表示標準輸入,1表示標準輸出,2表示錯誤輸出,這裡將1傳入EBX,也就是表示標準輸出

ECX包含字串的開頭

EDX包含字串的長度

用樣,下面也是系統調用 ,1表示退出函數,返回值為0

        movl $1, %eaxmovl $0, %ebxint  $0x80

編譯運行結果如下:


先解釋編譯參數,

第一步:首先編譯成二進位檔案  as --32 -o hellowrold.o hellowrold.s

as表示用as彙編器,

--32表示將目標代碼編譯成ia-32代碼格式

-o hellowrold.o 表示目標檔案是hellowrold.o(好像,寫錯檔案名稱了Orz)

hellowrold.s就是原始碼了(本來要定成helloworld.s的,錯了就錯了吧)

第二步:然後,將hellowrold.o連結成可執行檔

ld -m elf_i386 -o hellowrold hellowrold.o 

ld表示是用ld連結

-m elf_i386 表示產生32 elf位 elf格式檔案

-o hellowrold表示產生的檔案是hellowrold

hellowrold.o 是在第一階段產生的二進位檔案


再來試試gdb這個調試工具,彙編器as的多了個參數 -g,表示產生debug 代碼。gdb  hellowrold運行調試,介面如下:

gdb的用法主要有幾個:list顯示代碼,break設定段點, info register顯示所有寄存器的值,print列印特定變數的值,x顯示特定記憶體位置的值,step下一指令,run運行代碼。

示範一下:

list,列出代碼


break設定斷點,這裡是在特定的標籤中設定,break有以下方式設定斷點:

1.到達某個標籤

2.到達原始碼中的某個行號

3.資料值到達特定值

4.函數執行了指寶的次數之後


print 列印出相應的值,print 的輸出格式有:

print/d 輸出十進位值

print/t  輸出二進位值

print/x 輸出十六進位值


info register 列印出所有寄存器值


當然,我們的例子只要改一下,將 代碼入口標籤_start改成main就可以用gcc來編譯。

gcc -m32 -o hellowrold hellowrold.s  


就可以編譯成功了。

例二、下面再說個在組合語言中調用c函數庫的例子。

.section .dataoutput:.ascii "The number is %d\n".section .bss.lcomm buffer,18.section .text.globl _start_start:pushl $520pushl $outputcall  printfaddl  $8,%esppushl $0call  exit
如下方法編譯該代碼,可以看出,ld連結的時候多了幾個參數。

讓我來一一說一下多出來的兩個參數的含義吧。

我們知道 ,在linux中,把C函數串連到組合語言程式有兩種方法。第一種中做靜態連結(static linking).靜態連結把函數目標代碼直接連接到應用 程式的可執行程式檔案中。這樣會建立巨大的可執行程式,而且,如果同時運行程式的多個執行個體,會造 成內在浪費(每個函數都有其自己的相同函數拷貝)

第二種方法是動態連結。

在Linux中,標準C的動態庫位於lib.so.x檔案中,在我的系統(ubutnu 14.04 )中,這個檔案是libc.so.6,由於我採用相容方式運行,所以,我的系統有兩個該檔案,一個是32位的(/lib/i386-linux-gnu/libc.so.6),還有一個是64位的(/lib/x86_64-linux-gnu/libc.so.6)。在使用gcc時,gcc是自動將c語言連結到該庫,我們使用ld,為了連結libc.so檔案,必須使用gnu連接器的-l 參數,不用指定完整的庫名稱。連接器假設在它能找到的位置存在libxso檔案,基中x是命令列參數指定的庫名稱,我們的是c,故使用

-lc

理論上,我們不用加參數 -dynamic-linker就可以運行了,可事實上,編譯是通過了,但是運行不了。

bash: ./print: No such file or directory
為什麼呢?
問題在於連接器是能夠解析C函數了,但是函數本身沒有包含在最終可執行程式中。連結器假設運行時程式能夠找到該庫檔案,所以編譯進不出錯。但事實上,我們的程式找不到該庫檔案。為瞭解決這個問題,還必須指定在程式運行時載入動態庫的程式。對於LINUX,這個程式是linux.so.2,在我的系統下,它位於/lib下。為了指定這個程式,必須使用gnu連結器的 -dynamic-linker,故還要添加參數

-dynamic-linker
其實,我們也可以直接用 gcc編譯,只要把_start標籤改成 main就可以如下方法 編譯了

gcc -o print print.s



聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.