天天看点

(转)如何将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]st:/# 
           

使用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

(转)如何将arm-linux-gcc编译的动态链接helloworld在Android上运行

我尝试把

/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程序又有了新的方案。