彙編總結-第一部分_3_彙編的程序組成

下面進入彙編程序怎麼編程的介紹。 

 

之前我就說過彙編的段一般分爲3種

·數據段   .data

·bss段    .bss

·文本段   .text

PS;  不要忘了,本質上都是二進制代碼.也就是說bss和數據段都是可移植的.爲了給操作系統區分,纔有這個分類.估計有些病毒就是用的這種方式吧.


注意這裏的段都可以多次出現.C語言中的未初始化的全局變量和靜態變量都是存儲於這個bss段。所以你應該猜到了吧?對於bss段而言,全部內容都會用0來初始化。並且注意bss段並不包含在可執行文件中。但是正如之前所強調的.BSS存放的是未初始化的全局變量靜態變量,數據段存放的是初始化後的全局變量和靜態變量。

 

注意,這裏的三個段順序。除了bss段通常放在文本段之前,其餘的都可以隨便放。但是這裏就解釋不通爲什麼C語言中全局變量作用域範圍的問題了。在C語言中,全局變量申明的順序直接就影響了作用範圍,但是bss段的作用範圍是全局的。這是爲什麼呢?

初步估計是因爲編譯器的編譯方法的問題。因爲編譯原理中說過絕大部分的編譯器爲了效率是用,一邊掃描預處理,一邊構造參數表。所以在C中一定要先定義才能再用bss段中的數據。以後有時間自己用gcc看看這個構造過程。估計這單拿出來就可以寫一篇文章了。

補充:

在linux下調試過了。linux下gcc根本就沒有顯示.bss段。直接用的.comm來定義的全局變量。我在測試程序中main之上定義一個a,main之下定義一個b。那麼b其實是包含在main之中的。應該可以證實我的推論了。

 

不過,這裏如果3個段是不能直接使用的。爲了編譯器鏈接各個不通的段(我個人比較接受這個觀點,不過沒有驗證,如果有錯誤可以聯繫我),那麼還要用一個.section來申明段。

聲明一個段就像下面一樣

.section.data   注意後面只能跟一種類型。但是可以跟多個標籤

補充:

加不加.section其實不一定。我在linux下調試之後發現定義全局變量的位置前就沒有這個標記。

 

這裏其實要注意,在C語言中一個函數的局部變量是通過棧(或者寄存器)來存儲的。所以當函數結束的時候,棧頂指針恢復。局部變量的數據全部丟失。但是靜態變量是放在bss段中的,所以不會被丟失。

一般C中的常量字符串就可以存在.data中.不過還得注意在常量字符串之前需要加一個.asciz來標識是一個結尾帶’\0’的串。所以對於調用C的庫函數的話一定要用這個標識。如果用.ascii來標識的話則沒有’\0’。爲了和C一致,就忘了.asciz吧。

聲明一個.asicz的字符串常量就像這樣:
.section .rodata

zifuchuan:

.asicz “The Bigbang system”

這樣Zifuchuan這個標籤就相當於是一個字符串常量指針了。rodata標識只讀的數據。

關於.rodata可能也用於const指定的變量吧。一般const變量會被編譯器直接優化掉。我估計就當作data段了吧。

 

還有一個關鍵字需要介紹,那就是.globl了。這個聲明的作用是來讓外部程序可以訪問用此命令聲明的標籤。一般程序的其實標籤_start就需要用這個來聲明。就像下面這樣

.section .text

.globl  _start

_start:

一般as編譯器會吧這個當作程序的起始地址標籤,相當於C中的main(有些彙編器起始標籤可能也用main)。

 

注意,如果用GDB調試的時候將斷點設置爲_start標籤後面的一行的話,很可能程序會一直執行完,所以需要在_start 標籤之後加一條nop 指令。

 

前面講到可以調用C的庫函數。這裏需要注意一點彙編沒有C一樣可以有預處理先include一個.h文件。那麼計算機如何直到到哪去找這個函數呢?所以在鏈接.o文件的時候就需要鏈接庫文件了。就象這樣:

ld -dynamic-linker /lib/ld-linux.so.2 –o 生成可執行程序名字 –lc  .o文件

這是動態鏈接的範例。靜態鏈接直接就ld將.o文件一個個列出來就行了。中間的可以省略。

 

PS:貌似ld-linux.so.2也有_start,所以可以直接運行這個庫。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章