2011-11-14 24 views
10

跟進Why is the ELF execution entry point virtual address of the form 0x80xxxxx and not zero 0x0?Why do virtual memory addresses for linux binaries start at 0x8048000?,爲什麼我不能讓ld使用不同的入口點比默認的ld -e爲什麼ELF入口點0x8048000不能使用「ld -e」選項更改?

如果我這樣做了,我要麼得到一個segmentation fault,返回代碼139,即使對於靠近默認入口點的地址。爲什麼?

編輯:

我會讓問題更具體:

 .text 
     .globl _start  
_start: 
     movl $0x4,%eax  # eax = code for 'write' system call 
     movl $1,%ebx   # ebx = file descriptor to standard output 
     movl $message,%ecx # ecx = pointer to the message 
     movl $13,%edx   # edx = length of the message 
     int $0x80   # make the system call 
     movl $0x0,%ebx  # the status returned by 'exit' 
     movl $0x1,%eax  # eax = code for 'exit' system call 
     int $0x80   # make the system call 
     .data 
     .globl message 
message:   
     .string "Hello world\n" # The message as data 

如果我編譯這個與as program.s -o program.o,然後用ld -N program.o -o programreadelf -l program顯示0x0000000000400078靜態鏈接它作爲文本的VirtAddr段和0x400078作爲入口點。在運行時,'Hello World」的打印。

然而,當我嘗試用ld -N -e0x400082 -Ttext=0x400082 program.o -o program鏈接(由4個字節移動文本段和入口點),程序會killed。與readelf -l檢查現在顯示兩個不同的頁眉

LOAD類型,一個在0x0000000000400082,一個在0x00000000004000b0。當我嘗試0x400086,所有的工作,並且只有一個LOAD部分。

  1. 這是怎麼回事?
  2. 我可以選擇哪些內存地址,哪些是我不能選擇的,爲什麼?

謝謝你。

+0

我也一直能夠修改與鏈接腳本的入口點:http://stackoverflow.com/a/30536800/895245 –

回答

24

我爲什麼不能使LD使用一個不同的切入點比LD -e

你肯定可以將默認。這個:

int foo(int argc, char *argv[]) { return 0; } 

gcc main.c -Wl,-e,foo 

不起作用,因爲執行不在main開始。它從_start開始,鏈接從crt0.o(glibc的一部分),並安排動態鏈接等事情來正確啓動。通過將_start重定向到foo,您已經繞過了所有需要glibc初始化的操作,所以這些操作都不起作用。

但是,如果你不需要動態鏈接,並且願意做glibc通常爲你做的事情,那麼你可以任意指定入口點。例如:

#include <syscall.h> 

int foo() 
{ 
    syscall(SYS_write, 1, "Hello, world\n", 13); 
    syscall(SYS_exit, 0); 
} 

gcc t.c -static -nostartfiles -Wl,-e,foo && ./a.out 
Hello, world 

哦,這個問題的標題與您的實際問題(壞主意(TM))不符。

要回答標題中的問題,您確定可以更改您的可執行文件所鏈接的地址。默認情況下,您將獲得0x8048000加載地址(僅限於32位; 64位默認值爲0x400000)。

您可以輕鬆地將其更改爲例如0x80000通過將-Wl,-Ttext-segment=0x80000添加到鏈接線。

更新:

然而,當我嘗試(由4個字節移動文本段和入口點)與LD -N -e0x400082 -Ttext = 0x400082 program.o -o程序鏈接時,程序將被殺害。

好了,就不可能分配Ttext0x400082而不違反.text部對齊約束(其4)。您必須保持.text地址至少與4字節邊界對齊(或更改所需的對齊方式.text)。

當我將起始地址設置爲0x400078,0x40007c,0x400080,0x400084,...,0x400098並使用GNU-ld 2.20.1時,該程序起作用。

但是,當我使用binutils的當前CVS快照時,該程序適用於0x400078,0x40007c,0x400088,0x40008c,並且被取消爲0x400080,0x400084,0x400090,0x400094,0x400098。這可能是鏈接器中的一個錯誤,或者我違反了其他約束(我雖然沒有看到它)。

在這一點上,如果你是真的感興趣,我建議下載binutils的來源,建設ld,並找出究竟是什麼原因引起的,以創建兩個PT_LOAD段,而不是一個。

更新2:具有重疊的LMA部分

隊新的細分市場。

啊!這意味着你需要將.data移開。這使得工作可執行:

ld -N -o t t.o -e0x400080 -Ttext=0x400080 -Tdata=0x400180 
+0

我更新了我的問題做出更好的榜樣不符合預期的工作。 – nh2

+0

謝謝你,很好的回答,我沒有考慮到這個問題。 – nh2

+0

我用git bisect找到binutils 2.20和2.21之間的變化,它介紹了你描述的變化。它被稱爲「elf.c(_bfd_elf_map_sections_to_segments):爲具有重疊LMA的部分強制新段」。 (http://repo.or.cz/w/binutils.git/commit/278c98e2ff1c95c8ad9579755abda467ea2bc1b4) – nh2

相關問題