日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【软件开发底层知识修炼】十一 链接器-链接脚本

發(fā)布時間:2023/12/10 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【软件开发底层知识修炼】十一 链接器-链接脚本 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

上一篇文章學(xué)習(xí)了鏈接器之-main函數(shù)不是第一個執(zhí)行的函數(shù):main函數(shù)不是第一個執(zhí)行的函數(shù)

今天繼續(xù)學(xué)習(xí)鏈接器,學(xué)習(xí)鏈接是如何動作的,從而引入鏈接腳本的概念。本文就學(xué)習(xí)鏈接腳本的概念。

1、鏈接腳本的作用

我們都知道可重定位文件經(jīng)過鏈接器鏈接后最終形成可執(zhí)行文件。這個鏈接的過程大概就是分為符號解析和重定位。

那么鏈接器到底是如何工作的呢?這取決于鏈接腳本。我們可以看下圖:

幾個可重定位文件與相應(yīng)的庫文件進行鏈接,鏈接器經(jīng)過鏈接器的指導(dǎo),最終形成可執(zhí)行程序。

在學(xué)習(xí)鏈接鏈接腳本的大致格式之前,先練總結(jié)一下鏈接腳本的幾個作用(實際上這些作用我們都知道,只不過今天才知道鏈接腳本的存在而已):

  • 鏈接腳本用于描述鏈接器處理目標(biāo)文件(可重定位文件)與庫文件的方式

  • 合并各個目標(biāo)文件中的段
  • 重定位各個段的起始地址
  • 重定位各個符號的最終地址(這個地址實際上是段內(nèi)偏移地址)

2、鏈接腳本的格式

鏈接腳本也就是一個腳本文件,語法比較簡單,下面我們直接看一個例子,來說明一個鏈接腳本大致有哪些內(nèi)容:

上述的的描述還是很全面很仔細的。我們主要注意一下幾點:

  • 各個段的鏈接地址必須符合具體平臺的規(guī)則,比如在Intel處理器上與在Amd處理器上,或許各個段在整個地址空間的位置就會有一些差別
  • 鏈接腳本中能夠直接定義標(biāo)識符并制定存儲地址
  • 鏈接腳本能夠直接定義源代碼(需要編譯的.c .c++程序)中的標(biāo)識符的地址
  • 我們主要學(xué)習(xí)Linux系統(tǒng),在Linux中代碼段(.text段的地址范圍為[0x08048000,0x08049000])

我們現(xiàn)在可能還不理解上面的幾條注意事項,但是經(jīng)過下面的例子,就一定可以理解了:

我們寫了如下的C程序與鏈接腳本:

8-1.c

#include <stdio.h>int s1; extern int s2;int main() {printf("&s1 = %p\n", &s1);printf("&s2 = %p\n", &s2);return 0; }

8-1.lds

SECTIONS {.text 0x08048400:{*(.text)}. = 0x01000000;s1 = .;. += 4;s2 = .;.data 0x0804a800:{*(.data)}.bss :{*(.bss)} }

我們看上面的程序,在C程序中有一個extern int s2; 這個s2不是這個C文件的,是外部文件的,很明顯,我們只有兩個文件,另一個就是我們指定的鏈接腳本文件。

使用下述命令進行編譯:

  • gcc 8-1.c 8-1.lds -o lyy

生成可執(zhí)行程序lyy (注意如果編譯的時候不加上我們自己定義的鏈接腳本,編譯就會出錯)

運行:

  • ./lyy

執(zhí)行結(jié)果為:

很明顯,s1的地址由于我們再鏈接腳本中指定了:

. = 0x01000000;s1 = .;

所以s1的地址是:0x01000000;

而由于在鏈接腳本中有如下的兩句話:

. += 4;s2 = .;

所以s2的地址為:0x01000004;

如果我們不使用鏈接腳本指定這兩個變量的地址,那么他們的地址就是隨機的,這也符合我們平時的結(jié)果。

3、借助鏈接腳本修改程序的入口函數(shù)

不知道是否還記得在上一篇文章中:點擊查看。我們學(xué)習(xí)了程序的執(zhí)行流程,知道了main函數(shù)并不是真正的第一個開始執(zhí)行的函數(shù)。而且我們有辦法在編譯程序的時候改變第一個執(zhí)行的程序。那個時候使用的是在編譯的時候指定入口函數(shù)的地址,就像下面這樣:

  • gcc -e program -nostartfiles program.c -o program

今天我們來學(xué)習(xí)另一種方法,來修改程序的入口函數(shù)。

那就是在鏈接腳本中指定,大概格式如下:

下面給出一個例子,這個例子中沒有main函數(shù),我們自己指定一個函數(shù),然后將它設(shè)為入口函數(shù):

8-2.c

#include <stdio.h> #include <stdlib.h>int program() {printf("D.T.Software\n");exit(0); }

8-2.lds

ENTRY(program)SECTIONS {.text 0x08048400:{*(.text)} }

使用下面命令進行編譯(也可以先編譯輸出目標(biāo)文件,然后進行鏈接,下面的命令直接一步完成而已):

  • gcc -nostartfiles 8-2.c 8-2.lds -o lyy2

沒有報錯,生成了可執(zhí)行文件lyy2

運行程序結(jié)果為:

很明顯,我們利用這個方法成功修改了這個C程序的入口函數(shù)。

為了更加深入,我們可以看看該可執(zhí)行程序的符號信息:

使用以下命令查看可執(zhí)行程序lyy2

  • nm lyy2

由于上面的8-2.lds鏈接腳本指定代碼段其實地址為: 0x08048400,而我們的可執(zhí)行程序的入口函數(shù)(program函數(shù))的地址其實就是代碼段(.text)地址,所以如上圖,T代表代碼段,地址為0x08048400。很完美的解釋。

4 、 默認的鏈接腳本

上面我們學(xué)習(xí)了鏈接腳本的各種知識,但是我們平時并沒有使用它或者看到它。但是這并不意味著學(xué)習(xí)它就沒有用處。它對于我們理解整個系統(tǒng)原理有很大幫助。

可以使用下面的命令查看默認的鏈接腳本:

  • ld --verbose > defaults.lds

上述命令將默認的鏈接腳本輸出到文件defaults.lds文件中,我們可以打開defaults.lds文件來查看默認鏈接腳本文件。

5、總結(jié)

記住,我們在學(xué)習(xí)的內(nèi)容是可以讓你走的更遠,走的更高的鋪墊。或許對你產(chǎn)生不了直接的影響,但是絕對會對你將來的學(xué)習(xí)之路產(chǎn)生深遠的影響。不要一口吃一個胖子,慢慢來,從應(yīng)用軟件做起,深入學(xué)習(xí)底層原理!你的未來一定更加美好!!!

本文參考狄泰軟件學(xué)院相關(guān)課程
想學(xué)習(xí)的可以加狄泰軟件學(xué)院群,
群聊號碼:199546072

學(xué)習(xí)探討加個人(可以免費幫忙下載CSDN資源):
qq:1126137994
微信:liu1126137994

總結(jié)

以上是生活随笔為你收集整理的【软件开发底层知识修炼】十一 链接器-链接脚本的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。