把這個程式儲存成檔案start.s(匯程式設計序通常以.s作為檔名字尾),用彙編器(assembler)as把匯程式設計序中的助記符翻譯成機器指令,生成目標檔案start.o:
$as start.s -o start.o
然後用鏈結器(linker,或link editor)ld把目標檔案start.o鏈結成可執行檔案start:
$ld start.o -o start
為什麼用彙編器翻譯成機器指令了還不行,還要有乙個鏈結的步驟呢?
現在執行這個程式,它只做了一件事就是退出,退出狀態是4(在shell中可以用特殊變數$?得到上一條命令的退出狀態):
$./start
$echo $?
所以這段彙編**相當於在c程式的main函式中retrun 4;。
下面逐行分析這個匯程式設計序。首先,#號表示單行注釋,類似於c語言的//注釋。
.section .data
匯程式設計序中以.開頭的名稱並不是指令的助記符,不會被翻譯成機器指令,而是給彙編器一些特殊指示,稱為彙編指示(assembler directive)或偽操作(pseudo-operation),由於他不是真正的指令所以加個「偽」字。 .section指示把**劃分成若干個段(section),程式被作業系統載入執行時,每個段被載入到不同的位址,作業系統對不同的頁面設定不同的讀、寫、執行許可權。 .data段儲存程式的資料,是可讀可寫的,相當於c程式的全域性變數。本程式中沒有定義資料,所以.data段是空的。
.section .text
.text段儲存**,是唯讀和可執行的,後面那些指令都屬於.text段。
.globl _start
_start是乙個符號(symbol),符號在匯程式設計序中代表乙個位址,可以用在指令中,匯程式設計序經過彙編器的處理後,所有的符號都被替換成它所代表的位址值。在c語言中我們通過變數名訪問乙個變數,其實就是讀寫某個位址的記憶體單元,我們通過函式名呼叫乙個函式,其實就是跳到該函式第一條指令所在的位址,所以變數名和函式名都是符號,本質上是代表記憶體位址的。
.globl只是告訴彙編器,_start這個符號要被鏈結器用到,所以要在目標檔案的符號表中標記它是乙個全域性符號。start就像c程式的main函式一樣特殊,是整個程式的入口,鏈結器在連線時會查詢目標檔案中的_start符號代表的位址,把它設定為整個程式的入口位址,所以每個匯程式設計序都要提供乙個_start符號並且用.globl宣告。如果乙個符號沒有用.globl宣告,就表示這個符號不會被鏈結器用到。
_start:
這裡定義了_start符號,彙編器在翻譯匯程式設計序是會計算每個資料物件和每條指令的位址,當看到這樣乙個符號定義時,就把他後面一條指令的位址作為這個符號所代表的位址。而_start這個符號又比較特殊,它所代表的位址是整個程式的入口位址,所以下一條指令movl $1, %eax就成了程式中第一條被執行的指令。
movl $1, %eax
這是一條資料傳送指令,這條指令要求cpu內部產生乙個數字1並儲存到exa暫存器中。mov的字尾l表示long,說明是32位的傳送指令。這條指令不要求cpu讀記憶體,1這個數是cpu內部產生的,稱為立即數(immediate)。在匯程式設計序中,立即數前面要加$,暫存器名前面要加%,以便跟符號名區分開。以後我們會看到mov指令還有另外幾種形式,但資料傳送方向是一樣的,第乙個運算元總是源運算元,第二個運算元總是目標運算元。
movl $4, %ebx
和上一條指令類似,生成乙個立即數4並儲存到ebx暫存器中。
int $0x80
前兩條指令都是為這條指令做準備的,執行這條指令時發生以下動作:
1. int指令稱為軟中斷指令,可以用這條指令故意產生乙個異常,異常的處理和中斷類似,cpu從使用者模式切換到特權模式,然後跳轉到核心**中執行異常處理程式。
2. int指令中的立即數0x80是乙個引數,在異常處理程式中要根據這個引數決定如何處理,在linux核心中int $0x80這種異常稱為系統呼叫(system call)。核心提供了很多系統服務工使用者程式使用,但這些系統服務不能像庫函式(比如printf())那樣呼叫,因為在執行使用者程式時cpu處於使用者使用者模式,不能直接呼叫核心函式,所以需要通過系統呼叫切換cpu模式,經由異常處理程式進入核心,使用者程式只能通過暫存器傳幾個引數,之後就要按核心設計好的**路線走,而不能由使用者程式隨心所欲,想調哪個核心函式就調哪個核心函式,這樣可以保證系統 服務被安全地呼叫。在呼叫結束之後,cpu再切換回使用者模式,繼續執行int $0x80的下一條指令,在使用者程式看來就像函式呼叫和返回一樣。
3. eax和ebx的值是傳遞給系統呼叫的兩個引數。eax的值是系統呼叫號,linux的各種系統呼叫都是由int $0x80指令引發的,核心需要通過eax判斷使用者要調哪個系統呼叫,exit的系統呼叫號是1。ebx的指示傳給exit的引數,表示退出狀態。大多數系統呼叫完成之後會返回使用者空間繼續執行後面的指令,而exit系統呼叫比較特殊,它會終止掉當前程序,而不是返回使用者空間繼續執行。
簡單的匯程式設計序分析
section data section text globl start start movl 1,eax movl 4,ebx int 0x80 將這段程式儲存為hello.s,然後用彙編器as把匯程式設計序中的助記符翻譯成機器指令 彙編指令與機器指令是對應的 生成目標檔案hello.o。然後用...
匯程式設計序 退出
作為第乙個匯程式設計序,本程式除了退出以外,並沒有執行其他的功能。目的 退出並向linux核心返回乙個狀態碼的簡單程式 輸入 無 輸出 返回乙個狀態碼.在執行程式後可通過輸入echo 來讀取狀態碼 變數 eax儲存系統呼叫號 ebx儲存返回狀態 section data section text g...
微機匯程式設計序
又是自學的一學期,呵呵。學到最後也就知道零星半點指令吧,複雜的程式可能還是不怎麼會寫,熟練當然也不敵c了,但是彙編之於嵌入式,往上走肯定少不了遇到,學好還是必要的!此次僅作入門吧。今日所學,明日之用。1 統計正負零的個數 datas segment array db 1,2,1,0,2,0,2,4,...