2015-05-09 65 views
1

所有討論都是針對x86的。執行共享目標文件

如果我寫了一個簡單的hello程序,如下面的一個:

#include <stdio.h> 

int main(){ 
    printf("Hello\n"); 
    return 0; 
} 

而且隨着Ubuntu的編譯我的電腦上

$gcc -shared -mPIC -o hello_new hello.c 

然後它會給我段錯誤,當我嘗試執行hello_new。將此二進制文件移至android手機時出現同樣的錯誤。 (但我可以將它編譯爲靜態鏈接libc的二進制文件並在android手機上運行它)

是的,我想直接執行共享對象。

原因如下: 我最近得到一個由其他人編譯的linux文件。當我使用linux命令filereadelf來分析文件。它說它是一個共享對象(32位,用-m32編譯)。但我可以在手機上執行Android中的可執行共享對象:

$./hello 

這真讓我困惑。這個共享目標文件包含printf函數調用,不確定它是靜態鏈接還是動態鏈接。但由於它可以通過ADB在Android上運行,因此我認爲它是靜態鏈接到libc的。

什麼樣的編譯技術可以允許直接執行共享對象?

+0

您的'gcc'設置爲ARM編譯?我不認爲你可以將x86可執行文件移植到ARMv7a設備上,並期望它可以正常工作。在x86安卓設備(例如模擬器)上嘗試它,或嘗試編譯目標處理器的體系結構。 – initramfs

+0

@CPUTerminator,都是x86。 – drdot

+0

嗯,我沒有太多可靠的依據,也許gcc使用的是不支持Android的指令/擴展。看看這個[鏈接](http://shareprogrammingtips.com/c-language-programming-tips/cross-compile-cc-based-programs-run-android-smart-phones/),而方法1似乎是與您的做法相同,它針對的是ARM體系結構。也許嘗試方法2和/或3? – initramfs

回答

0

我覺得你的android和pc都是x86或arm,否則可執行文件不能在兩個平臺上運行。現在要共享庫可執行文件,可以同時使用gcc的命令行選項-pie。詳情請見answer

+0

我不問如何生成共享對象。我要求編譯共享對象,以便它可以直接執行。 – drdot

0

恰巧我正在研究這種類型的東西。 Linux下可執行文件和共享對象之間的主要區別之一是可執行文件具有解釋器和(有效)入口點。 例如,在一個最小的程序:

$ echo 'int main;' | gcc -xc - 

如果你看一下它的精靈程序標題:

$ readelf --program-headers a.out 
    ... 
    INTERP   0x0000000000000200 0x0000000000400200 0x0000000000400200 
       0x000000000000001c 0x000000000000001c R  1 
     [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2] 
    ... 

解釋程序負責程序的執行,來實現這一點,它會執行一些初始化,如加載所需的共享對象。實際上,這與劇本shebang非常類似,但是對於elf文件。 在這種情況下,/lib64/ld-linux-x86-64.so.2是amd64的加載程序。你可以有倍數裝載機:例如,一個用於32位,一個是64

現在的切入點:

$ readelf --file-header a.out 
ELF Header: 
... 
    Entry point address:    0x4003c0 
... 
$ readelf -a a.out | grep -w _start 
    57: 00000000004003c0  0 FUNC GLOBAL DEFAULT 13 _start 

默認情況下,你可以看到_start被定義爲切入點。

所以,如果你考慮下面的小例子:

#include <unistd.h> 
#include <stdlib.h> 
#include <stdio.h> 
#ifdef INTERPRETER 
const char interp[] __attribute__((section(".interp"))) = INTERPRETER; 
#endif /* INTERPRETER */ 
void entry_point(void) { 
    fprintf(stderr, "hello executable shared object world !\n"); 
    _exit(EXIT_SUCCESS); 
} 

如果你編譯它作爲一個「正常」的共享對象並執行:

$ gcc libexecutable.c -Wall -Wextra -fPIC -shared -o libexecutable.so 
$ ./libexecutable.so 
Erreur de segmentation 

你可以看到它出現segfaults。但是現在,如果你定義一個解釋器(適應它的路徑是什麼readelf --program報頭之前給你),並告訴鏈接什麼是你的切入點:

$ gcc libexecutable.c -Wall -Wextra -fPIC -shared -o libexecutable.so -DINTERPRETER=\"/lib64/ld-linux-x86-64.so.2\" -Wl,-e,entry_point 
$ ./libexecutable.so hello executable shared object world ! 

現在它的工作原理。請注意,_exit()調用對於在執行結束時避免段錯誤是必要的。

但最後,請記住,因爲您指定了一個自定義入口點,您將根據需要繞過可能需要或不需要的libc初始化步驟。