1. 程式人生 > >(轉)如何將arm-linux-gcc編譯的動態連結helloworld在Android上執行

(轉)如何將arm-linux-gcc編譯的動態連結helloworld在Android上執行

如何將arm-linux-gcc編譯的動態連結helloworld在Android上執行

https://blog.csdn.net/kangear/article/details/78537352

標題起得有點長,但是少一個字都不足以描述清楚我要說的。Android上要用C程式無非兩種方法:1. NDK JNI 2. 使用arm-linux-gcc編譯的靜態連結程式;這兩種方法我使用了多年,比較方便。不過也有缺點前者缺點是使用c庫必須是Google為Android精簡的bionic而非長盛不衰的libgcc。後者的缺點是所有的程式必須編譯成靜態連結,不能有任何動態連結的成分(目前已經使用的比較順手的busybox tinyalsa ghostscript strace )。還有一種情況最近遇到的,一個廠商給提供了armel版本的可執行程式,其連結庫為動態連結,沒有原始碼可以編譯。這種情況下如果想要在Android上執行,那就得開闢第三條路了arm-linux-gcc編譯的動態連結程式在Android上的執行。

使用arm-linux-gcc編譯出來的helloworld程式,使用file檢視:

[email protected]:/# file a.out 
a.out: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.31, BuildID[sha1]=0x32063ae9956acd7eece720ad5ed5cd5dbcd63034, not stripped
[email protected]:/# 

使用readelf檢視:

[email protected]:/# readelf -d a.out 

Dynamic section at offset 0xf18 contains 24 entries:
  Tag        Type                         Name/Value
 0x00000001 (NEEDED)                     Shared library: [libc.so.6]
 0x0000000c (INIT)                       0x82bd
 0x0000000d (FINI)                       0x83e9
 0x00000019 (INIT_ARRAY)                 0x10f0c
 0x0000001b (INIT_ARRAYSZ)               4 (bytes)
 0x0000001a (FINI_ARRAY)                 0x10f10
 0x0000001c (FINI_ARRAYSZ)               4 (bytes)
 0x6ffffef5 (GNU_HASH)                   0x81ac
 0x00000005 (STRTAB)                     0x8228
 0x00000006 (SYMTAB)                     0x81d8
 0x0000000a (STRSZ)                      65 (bytes)
 0x0000000b (SYMENT)                     16 (bytes)
 0x00000015 (DEBUG)                      0x0
 0x00000003 (PLTGOT)                     0x11000
 0x00000002 (PLTRELSZ)                   32 (bytes)
 0x00000014 (PLTREL)                     REL
 0x00000017 (JMPREL)                     0x829c
 0x00000011 (REL)                        0x8294
 0x00000012 (RELSZ)                      8 (bytes)
 0x00000013 (RELENT)                     8 (bytes)
 0x6ffffffe (VERNEED)                    0x8274
 0x6fffffff (VERNEEDNUM)                 1
 0x6ffffff0 (VERSYM)                     0x826a
 0x00000000 (NULL)                       0x0
[email protected]
:/#

可以看到其只是連結到一個libc.so.6,將libc.so.6放到/system/lib/中之後,執行這個helloworld還是No such file or directory

/system/bin/sh: ./a.out: No such file or directory

使用strace也跟蹤不到任何資訊:

[email protected]: # strace ./a.out            
execve("./a.out", ["./a.out"], [/* 23 vars */]) = -1 ENOENT (No such file or directory)
write(2, "strace: exec: No such file or di"..., 40strace: exec: No such file or directory
) = 40
mprotect(0xb6efa000, 4096, PROT_READ|PROT_WRITE) = 0
mprotect(0xb6efa000, 4096, PROT_READ)   = 0
close(0)                                = 0
close(1)                                = 0
close(2)                                = 0
futex(0xb6fa45a0, FUTEX_WAKE_PRIVATE, 2147483647) = 0
mprotect(0xb6efa000, 4096, PROT_READ|PROT_WRITE) = 0
mprotect(0xb6efa000, 4096, PROT_READ)   = 0
munmap(0xb6efa000, 4096)                = 0
exit_group(1)                           = ?
+++ exited with 1 +++
1|[email protected]: #

看過How do you cross compile ELF executables for Android?之後,明白了一個C程式的執行是靠linker來操作的,Android自帶的linker是/system/bin/linker。arm-linux-gcc預設使用的是/lib/ld-linux.so.3

我嘗試把/lib/ld-linux.so.3軟連結到/system/bin/linker再次執行會怎麼樣

[email protected]:/ # mount -o remount /
[email protected]:/ # mkdir /lib
[email protected]:/ # ln -s /system/bin/linker /lib/ld-linux.so.3
[email protected]:/ # ./a.out                                 
error: only position independent executables (PIE) are supported.
1|[email protected]:/ # 

這次總算不出現No such file or directory但是Android的PIE機制導致它還不能執行。這個順著繞過android 5.0以上的pie機制進行解決。還會遇到如下錯誤,看來使用/system/bin/linker並不是一個好的辦法。

empty/missing DT_HASH in libx.so (built with --hash-style=gnu?)

使用真正的/lib/ld-linux.so.3,把交叉工具鏈中的這個檔案,拷貝到開發板上的對應位置。再執行時就會出現:

[email protected]:/ # ./a.out                   
./a.out: error while loading shared libraries: libc.so.6: cannot open shared object file: No such file or directory
127|[email protected]:/ # 

看到這個就比較熟悉了,將其缺少的庫檔案push到/system/lib/中,就可以運行了:

[email protected]:/ # /a.out                                                                        
Hello World!
[email protected]:/ # 

小結:

至此在Android上編譯(或者移植)C程式又有了新的方案。