為了研究elf檔案裝載到記憶體的**,以及從**開始執行程式,環境:ubuntu12.04 64位,gcc4.6.3。
使用的源**是:
#include void hello(void)
int main(void)
程式並不是從main函式開始執行的,gcc -o main main.c時,缺省會連線libc.so(可以指定-nodefaultlib, -nostdlib取消連線),並且會新增乙個啟動**_start函式(可以指定-nodefaultlib, -nostdlib不新增啟動**),用於初始化,並提供main函式的argc, argv等引數,_start函式中會呼叫main函式。
$ readelf -d main
dynamic section at offset 0xe50 contains 20 entries:
tag type name/value
0x0000000000000001 (needed) shared library: [libc.so.6]
0x000000000000000c (init) 0x400390
0x000000000000000d (fini) 0x4005c8
$ objdump -d main | grep _start
400394: e8 63 00 00 00 callq 4003fc 00000000004003b0 <__libc_start_main@plt-0x10>:
00000000004003c0 <__libc_start_main@plt>:
00000000004003d0 <_start>:
4003f4: e8 c7 ff ff ff callq 4003c0 <__libc_start_main@plt>
readelf -h main | grep entry可以看到:
entry point address: 0x4003d0
程式的入口位址是0x4003d0,也就是_start函式的位址,程式裝載到記憶體後,從0x4003d0(_start)開始執行。
那麼,我不想執行_start函式呢,可以通過ld的引數-e指定入口函式,使用gcc -o main mian.c -wl,-ehello編譯,-wl用於指定後面的引數是給ld的,-e指定入口函式是hello。
證明了-wl,-ehello可以指定程式的入口函式為hello。$ ./main
$ echo $?
42
$ objdump -d main | grep hello
00000000004004f4 :
$ readelf -h main | grep entry
entry point address: 0x4004f4
那麼程式的入口位址0x4004f4是怎麼來的呢?
0x4f4其實是hello函式在elf檔案中的偏移量,可以通過hexdump -c main | grep -a5 -b5 4f0檢視到
$ hexdump -c main | grep -a5 -b5 4f0
000004a0 0b 20 00 ff 14 c5 38 0e 60 00 48 8b 05 77 0b 20 |. ....8.`.h..w. |
000004b0 00 48 39 d8 72 e2 c6 05 63 0b 20 00 01 48 83 c4 |.h9.r...c. ..h..|
000004c0 08 5b 5d c3 66 66 66 2e 0f 1f 84 00 00 00 00 00 |..fff.........|
000004d0 48 83 3d 70 09 20 00 00 55 48 89 e5 74 12 b8 00 |h.=p. ..uh..t...|
000004e0 00 00 00 48 85 c0 74 08 5d bf 48 0e 60 00 ff e0 |...h..t.].h.`...|
000004f0 5d c3 90 90 55 48 89 e5 bf 2a 00 00 00 e8 fe fe |]...uh...*......|
00000500 ff ff 55 48 89 e5 b8 18 00 00 00 5d c3 90 90 90 |..uh.......]....|
00000510 48 89 6c 24 d8 4c 89 64 24 e0 48 8d 2d 03 09 20 |h.l$.l.d$.h.-.. |
00000520 00 4c 8d 25 fc 08 20 00 4c 89 6c 24 e8 4c 89 74 |.l.%.. .l.l$.l.t|
00000530 24 f0 4c 89 7c 24 f8 48 89 5c 24 d0 48 83 ec 38 |$.l.|$.h.\$.h..8|
00000540 4c 29 e5 41 89 fd 49 89 f6 48 c1 fd 03 49 89 d7 |l).a..i..h...i..|
然後objdump -d main | grep -a5 -b5 hello檢視hello對應的機器碼:
$ objdump -d main | grep -a5 -b5 hello
4004f0: 5d pop %rbp
4004f1: c3 retq
4004f2: 90 nop
4004f3: 90 nop
00000000004004f4 :
4004f4: 55 push %rbp
4004f5: 48 89 e5 mov %rsp,%rbp
4004f8: bf 2a 00 00 00 mov $0x2a,%edi
4004fd: e8 fe fe ff ff callq 400400
證明了這一點。
然後0x400000是什麼呢?
這個是elf裝載到記憶體時的起始位置,可以通過ld的引數-wl,-ttext-segment,0x400000指定,比如我們gcc -o main main.c -wl,-ehello -wl,-ttext-segment,0x4200000編譯程式,給程式換乙個裝載位址,然後readelf -h main | grep entry得到:
entry point address: 0x42004f4
$ objdump -d main | grep hello -a 10
00000000042004f4 :
42004f4: 55 push %rbp
42004f5: 48 89 e5 mov %rsp,%rbp
42004f8: bf 2a 00 00 00 mov $0x2a,%edi
42004fd: e8 fe fe ff ff callq 4200400 0000000004200502 :
4200502: 55 push %rbp
4200503: 48 89 e5 mov %rsp,%rbp
4200506: b8 18 00 00 00 mov $0x18,%eax
420050b: 5d pop %rbp
注意1、-ttext-segment指定的必需是乙個頁對齊的位址。
2、動態庫的裝載位置不是固定的,一般可以認為動態庫的-ttext-segment=0,沒有使用;如果想直接執行.so的話(glibc裡面很多.so都可以直接執行),需要為.so指定ld-linux.so(.so預設沒有指定):
gcc -shared -fpic -o libx.so x.c -wl,--dynamic-linker=some_ld_linux.so.x
或者**裡面寫:const char my_interp __attribute__((section(".interp"))) = "/lib/ld-linux.so.3"; //需要保證這個ld-linux.so存在且能用
可以使用readelf -l檢視.inter段,也就是指定的ld-linux.so
3、-ttext-segment並不是指定.text段的載入位置,而是指定整個elf的載入位置。
如果想指定.text段的載入位置,可以:
-tbss=org
-tdata=org
-ttext=org
same as --section-start, with ".bss", ".data" or ".text" as the
sectionname.
4、gcc -wl,-ttext-segment=0x400000 -wl,-ttext=0x800000 -o x x.c這樣是可以的,但是如果-ttext指定的比較小,要麼程式無法執行,要麼可能和其他段衝突。加完-ttext之後,.text段以及後面的段,在檔案中的偏移會變大不少,中間填充的0是為了載入到記憶體後的頁對齊,在記憶體中的載入位置都會從-ttext指定的位置開始。
軟裝和硬裝又有哪些不同?
所謂軟裝,是相對硬裝而言的,硬裝一般指的室內裝修中固定的 不能移動的裝飾物如吊頂 牆面造型 地面裝飾 門窗工程等,軟裝是除掉硬裝,進行家居的二度裝飾,它是可以移動的 易於更換的飾物,如頂部燈具 牆面窗簾 桌布 掛畫 地面可移動家具 沙發 抱枕 地毯 臥室床上用品等以及裝飾工藝品 居室植物等。我今天發...
集合和JSON裝換
使用json lib將pagebean物件轉為json,通過輸出流寫回頁面中 jsonobject 將單一物件轉為json jsonarray 將陣列或者集合物件轉為json 注 需要將引用型別的去掉,否則會報錯,迴圈引用 public string findall throws ioexcepti...
裝tomcat和nginx心得
開機啟動tomcat 1 在 etc rc.d init.d目錄下生成乙個檔案tomcat8080 2 在檔案裡新增如下內 bin bash 2345linux執行級別 10開機啟動優先順序,數值越大越排在前面,最大值100 90關機優先順序 chkconfig 2345 10 90 descrip...