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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

汇编语言使用C库函数和Linux动态链接

發布時間:2023/11/27 生活经验 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 汇编语言使用C库函数和Linux动态链接 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

使用printf


代碼

#cpuid2.s -- Using C labrary calls  
.section .data  
output:          .asciz "The processor Vender is '%s'\n"
.section .bss          .lcomm buffer, 12  
.section .text  
.globl _start  
_start:          movl $0, %eax          cpuid          movl $buffer, %edi          movl %ebx, (%edi)   //含義同cpuid.s,向%edi所指向的buffer內存          movl %edx, 4(%edi)  //位置寫入3個寄存器的內容,這3個寄存器存儲了          movl %ecx, 8(%edi)  //CPU廠商信息的字符串(12字節)          pushl $buffer       //將buffer和output入棧,為printf提供參數          pushl $output          call printf         //調用C的printf函數          addl $8, %esp       //將堆棧指針回滾8個字節,達到清除printf參數的目的          pushl $0          call exit


?

.asciz是在定義字符串的時侯在字符串結尾加上空字符(即C語言的\0),這樣做的目的是為了讓printf能讀懂字符串。

.lcomm是在本地內存區域中聲明固定長度的未初始化數據,這里初始化了12個字節的空間。

程序里buffer和output內存位置的內容是要向printf傳遞的參數值:

一個是"The processor Vender is '%s'\n"字符串;

另外一個是由cpuid返回結果(在ebx,edx,ecx三個寄存器中)填充的buffer。


需要通過堆棧來傳遞參數,所以在程序中使用

pushl $buffer

pushl $output

將參數入棧,printf獲取參數是自右向左,即先buffer后output,所以要把buffer后入棧。

參數入棧之后,用call指令調用printf。

exit的情況同上,使用了一個參數--常數0。


匯編

#as -o cpuid2.o cpuid2.s

采用了動態連接的方式,所以C函數沒有包含在可執行程序中,需要由另外的程序在運行時加載,ld不知道這個程序在哪里,所以我們還得手動指定

動態鏈接

#ld -dynamic-linker /lib/ld-linux.so.2 -lc -o cpuid2 cpuid2.o

#./cpuid2

輸出

The processor Vendor ID is 'GenuineIntel'

GDB調試

# gdb cpuid2  
GNU gdb (GDB) Red Hat Enterprise Linux (7.2-56.el6)
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /usr/zhms/AS/chap04/cpuid2...done.
(gdb) break _start
Breakpoint 1 at 0x80481b8: file cpuid2.s, line 10.
(gdb) r
Starting program: /usr/zhms/AS/chap04/cpuid2 Breakpoint 1, _start () at cpuid2.s:10
10          movl $0, %eax
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.80.el6_3.6.i686
(gdb) i r
eax            0x0      0
ecx            0x0      0
edx            0x758470 7701616
ebx            0x767fc4 7765956
esp            0xbffff6c0       0xbffff6c0
ebp            0x0      0x0
esi            0xbffff6cc       -1073744180
edi            0x80481b8        134513080
eip            0x80481b8        0x80481b8 <_start>
eflags         0x286    [ PF SF IF ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x33     51
(gdb) s
11          cpuid
(gdb) i r
eax            0x0      0
ecx            0x0      0
edx            0x758470 7701616
ebx            0x767fc4 7765956
esp            0xbffff6c0       0xbffff6c0
ebp            0x0      0x0
esi            0xbffff6cc       -1073744180
edi            0x80481b8        134513080
eip            0x80481bd        0x80481bd <_start+5>
eflags         0x286    [ PF SF IF ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x33     51
(gdb) s
13          movl %ebx, (%edi)
(gdb) i r
eax            0x5      5
ecx            0x6c65746e       1818588270
edx            0x49656e69       1231384169
ebx            0x756e6547       1970169159
esp            0xbffff6c0       0xbffff6c0
ebp            0x0      0x0
esi            0xbffff6cc       -1073744180
edi            0x80492c0        134517440
eip            0x80481c4        0x80481c4 <_start+12>
eflags         0x286    [ PF SF IF ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x33     51
(gdb) s
14          movl %edx, 4(%edi)
(gdb) i r
eax            0x5      5
ecx            0x6c65746e       1818588270
edx            0x49656e69       1231384169
ebx            0x756e6547       1970169159
esp            0xbffff6c0       0xbffff6c0
ebp            0x0      0x0
esi            0xbffff6cc       -1073744180
edi            0x80492c0        134517440
eip            0x80481c6        0x80481c6 <_start+14>
eflags         0x286    [ PF SF IF ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x33     51
(gdb) s
15          movl %ecx, 8(%edi)
(gdb) i r
eax            0x5      5
ecx            0x6c65746e       1818588270
edx            0x49656e69       1231384169
ebx            0x756e6547       1970169159
esp            0xbffff6c0       0xbffff6c0
ebp            0x0      0x0
esi            0xbffff6cc       -1073744180
edi            0x80492c0        134517440
eip            0x80481c9        0x80481c9 <_start+17>
eflags         0x286    [ PF SF IF ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x33     51
(gdb) s
16          pushl $buffer
(gdb) i r
eax            0x5      5
ecx            0x6c65746e       1818588270
edx            0x49656e69       1231384169
ebx            0x756e6547       1970169159
esp            0xbffff6c0       0xbffff6c0
ebp            0x0      0x0
esi            0xbffff6cc       -1073744180
edi            0x80492c0        134517440
eip            0x80481cc        0x80481cc <_start+20>
eflags         0x286    [ PF SF IF ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x33     51
(gdb) s
17          pushl $output
(gdb) i r
eax            0x5      5
ecx            0x6c65746e       1818588270
edx            0x49656e69       1231384169
ebx            0x756e6547       1970169159
esp            0xbffff6bc       0xbffff6bc
ebp            0x0      0x0
esi            0xbffff6cc       -1073744180
edi            0x80492c0        134517440
eip            0x80481d1        0x80481d1 <_start+25>
eflags         0x286    [ PF SF IF ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x33     51
(gdb) s
18          call printf
(gdb) i r
eax            0x5      5
ecx            0x6c65746e       1818588270
edx            0x49656e69       1231384169
ebx            0x756e6547       1970169159
esp            0xbffff6b8       0xbffff6b8
ebp            0x0      0x0
esi            0xbffff6cc       -1073744180
edi            0x80492c0        134517440
eip            0x80481d6        0x80481d6 <_start+30>
eflags         0x286    [ PF SF IF ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x33     51
(gdb) s
0x007b63e0 in printf () from /lib/libc.so.6
(gdb) i r
eax            0x5      5
ecx            0x6c65746e       1818588270
edx            0x49656e69       1231384169
ebx            0x756e6547       1970169159
esp            0xbffff6b4       0xbffff6b4
ebp            0x0      0x0
esi            0xbffff6cc       -1073744180
edi            0x80492c0        134517440
eip            0x7b63e0 0x7b63e0 <printf>
eflags         0x246    [ PF ZF IF ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x33     51
(gdb) s
Single stepping until exit from function printf,
which has no line number information.
The processor Vendor ID is 'GenuineIntel'
_start () at cpuid2.s:19
19          addl $8, %esp
(gdb) i r
eax            0x2a     42
ecx            0xbffff6a0       -1073744224
edx            0x8fe364 9429860
ebx            0x756e6547       1970169159
esp            0xbffff6b8       0xbffff6b8
ebp            0x0      0x0
esi            0xbffff6cc       -1073744180
edi            0x80492c0        134517440
eip            0x80481db        0x80481db <_start+35>
eflags         0x286    [ PF SF IF ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x33     51
(gdb) s
20          pushl $0
(gdb) i r
eax            0x2a     42
ecx            0xbffff6a0       -1073744224
edx            0x8fe364 9429860
ebx            0x756e6547       1970169159
esp            0xbffff6c0       0xbffff6c0
ebp            0x0      0x0
esi            0xbffff6cc       -1073744180
edi            0x80492c0        134517440
eip            0x80481de        0x80481de <_start+38>
eflags         0x296    [ PF AF SF IF ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x33     51
(gdb) s
21          call exit
(gdb) i r
eax            0x2a     42
ecx            0xbffff6a0       -1073744224
edx            0x8fe364 9429860
ebx            0x756e6547       1970169159
esp            0xbffff6bc       0xbffff6bc
ebp            0x0      0x0
esi            0xbffff6cc       -1073744180
edi            0x80492c0        134517440
eip            0x80481e0        0x80481e0 <_start+40>
eflags         0x296    [ PF AF SF IF ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x33     51
(gdb) s
0x00799060 in exit () from /lib/libc.so.6
(gdb) i r
eax            0x2a     42
ecx            0xbffff6a0       -1073744224
edx            0x8fe364 9429860
ebx            0x756e6547       1970169159
esp            0xbffff6b8       0xbffff6b8
ebp            0x0      0x0
esi            0xbffff6cc       -1073744180
edi            0x80492c0        134517440
eip            0x799060 0x799060 <exit>
eflags         0x246    [ PF ZF IF ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x33     51
(gdb) s
Single stepping until exit from function exit,
which has no line number information.Program exited normally.
(gdb) i r
The program has no registers now.
(gdb) 


?

ld-linux.so查找共享庫的順序

這里引出一個問題,怎么知道ld-linux.so.2是什么以及定位

Glibc安裝的庫中有一個為ld-linux.so.X,其中X為一個數字,在不同的平臺上名字也會不同。可以用ldd查看:

#ldd /bin/cat

最后一個沒有=>的就是。其中第一個不是實際的庫文件,你是找不到的,它是一個虛擬庫文件用于和kernel交互。
ld-linux.so是專門負責尋找庫文件的庫。以cat為例,cat首先告訴ld-linux.so它需要libc.so.6這個庫文件,ld-linux.so將按一定順序找到libc.so.6庫再給cat調用。
那ld-linux.so又是怎么找到的呢?其實不用找,ld-linux.so的位置是寫死在程序中的,gcc在編譯程序時就寫死在里面了。Gcc寫到程序中ld-linux.so的位置是可以改變的,通過修改gcc的spec文件。

運行時,ld-linux.so查找共享庫的順序
(1)ld-linux.so.6在可執行的目標文件中被指定,可用readelf命令查看
(2)ld-linux.so.6缺省在/usr/lib和lib中搜索;當glibc安裝到/usr/local下時,它查找/usr/local/lib
(3)LD_LIBRARY_PATH環境變量中所設定的路徑
(4)/etc/ld.so.conf(或/usr/local/etc/ld.so.conf)中所指定的路徑,由ldconfig生成二進制的ld.so.cache中

編譯時,ld-linux.so查找共享庫的順序
(1)ld-linux.so.6由gcc的spec文件中所設定
(2)gcc --print-search-dirs所打印出的路徑,主要是libgcc_s.so等庫。可以通過GCC_EXEC_PREFIX來設定
(3)LIBRARY_PATH環境變量中所設定的路徑,或編譯的命令行中指定的-L/usr/local/lib
(4)binutils中的ld所設定的缺省搜索路徑順序,編譯binutils時指定。(可以通過“ld --verbose | grep SEARCH”來查看)
(5)二進制程序的搜索路徑順序為PATH環境變量中所設定。一般/usr/local/bin高于/usr/bin
(6)編譯時的頭文件的搜索路徑順序,與library的查找順序類似。一般/usr/local/include高于/usr/include


用 Linux 進行動態鏈接

ELF映像

Linux 中的動態鏈接的共享庫的過程。當用戶啟動一個應用程序時,它們正在調用一個可執行和鏈接格式(Executable and Linking Format,ELF)映像。內核首先將 ELF 映像加載到用戶空間虛擬內存中。然后內核會注意到一個稱為 .interp 的 ELF 部分,它指明了將要被使用的動態鏈接器(例如:/lib/ld-linux.so)。


一個ELF頭在文件的開始,保存了路線圖(road map),描述了該文件的組織情況。sections保存著object 文件的信息,從連接角度看:包括指令,數據,符號表,重定位信息等等。

?

使用 readelf 來顯示程序標題

#readelf -l cpuid2

注意,ld-linux.so 本身就是一個 ELF 共享庫,但它是靜態編譯的并且不具備共享庫依賴項。當需要動態鏈接時,內核會引導動態鏈接(ELF 解釋器),該鏈接首先會初始化自身,然后加載指定的共享對象(已加載則不必)。接著它會執行必要的再定位,包括目標共享對象所使用的共享對象。


#readelf -l cpuid2.o

There are no program headers in this file.


ldd命令

Linux 提供了很多種查看和解析 ELF 對象(包括共享庫)的工具。其中最有用的一個當屬 ldd命令,可以使用它來發現共享庫依賴項

#ldd cpuid2

ldd所告訴您的是:該 ELF 映像依賴于 linux-gate.so(一個特殊的共享對象,它處理系統調用,它在文件系統中無關聯文件),GNU C庫(libc.so)以及 Linux 動態加載器(因為它里面有共享庫依賴項)。


#ldd cpuid2.o

ldd: 警告: 你沒有執行權限 `./cpuid2.o'
不是動態可執行文件


readelf識別對象內可再定位的C庫

readelf 命令是一個有很多特性的實用程序,它讓您能夠解析和讀取 ELF 對象。readelf 有一個有趣的用途,就是用來識別對象內可再定位的項。對于我們這個簡單的程序來說,可以看到需要再定位的符號

#readelf -r cpuid2

從這個列表中,您可以看到各種各樣的需要再定位(到 libc.so)的 C庫調用。


#readelf -r cpuid2.o



readelf查看共享庫的依賴庫(NEEDED)和搜索名(SONAME)

#readelf -d cpuid2


#readelf -d cpuid2.o

無輸出


readelf查看ELF頭信息

#readelf -h cpuid2


#readelf -h cpuid2.o


附錄

#man readelf

?

objdump

objdump是用查看目標文件或者可執行的目標文件的構成的GCC工具


反匯編

#objdump -d cpuid2

對于其中的反匯編代碼

左邊是機器指令的字節,右邊是反匯編結果。顯然,所有的符號都被替換成地址了, 注意沒有加$的數表示內存地址,而不表示立即數。


objdump -x obj 以某種分類信息的形式把目標文件的數據組織(被分為幾大塊)輸出 <可查到該文件的所有動態庫>
objdump -t obj 輸出目標文件的符號表()
objdump -h obj 輸出目標文件的所有段概括()
objdump -j .text/.data -S obj 輸出指定段的信息,大概就是反匯編源代碼把
objdump -S obj C語言與匯編語言同時顯示


更多參考

#man objdump

?

?

參考:Linux 動態庫剖析

http://www.ibm.com/developerworks/cn/linux/l-dynamic-libraries/

總結

以上是生活随笔為你收集整理的汇编语言使用C库函数和Linux动态链接的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。