V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
FranzKafka95
V2EX  ›  问与答

Android Native 中编译的 binary 为什么会存在 SONAME

  •  
  •   FranzKafka95 · 304 天前 · 724 次点击
    这是一个创建于 304 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近在移植 AOSP14 ,遇到一个百思不得其解的问题。在我此前的认知里 binary=executable=可执行文件,源码实现时一定是以 main 函数作为入口 entry 的,直到今天我发现一个有意思的程序。

    前提:
    运行环境:AOSP14 Cuttlefish Virtual Machine

    该程序位于/apex/com.android.runtime/bin 目录,我们先用 file 命令看看:

    86_64:/apex/com.android.runtime/bin # file linker64
    linker64: ELF shared object, 64-bit LSB x86-64, BuildID=c8f402abba648f1ad456bbf0b9cd3e7a, not stripped
    
    

    看上去正常,我们使用 readelf 查看一下:

    86_64:/apex/com.android.runtime/bin # readelf -d linker64 | grep SONAME  
    0x000000000000000e (SONAME)             Library soname: [ld-android.so]  
    

    这怎么会有个 SONAME 呢,按道理这是个 binary ,不是个 shared library,接着我们再看看其所拥有的 program headers:

    86_64:/apex/com.android.runtime/bin # readelf -l linker64
    
    Elf file type is DYN (Shared object file)
    Entry point 0x68390
    There are 10 program headers, starting at offset 64
    
    Program Headers:
      Type           Offset   VirtAddr           PhysAddr           FileSiz MemSiz  Flg Align
      PHDR           0x000040 0x0000000000000040 0x0000000000000040 0x00230 0x00230 R   0x8
      LOAD           0x000000 0x0000000000000000 0x0000000000000000 0x46b54 0x46b54 R   0x1000
      LOAD           0x046b60 0x0000000000047b60 0x0000000000047b60 0x101e10 0x101e10 R E 0x1000
      LOAD           0x148970 0x000000000014a970 0x000000000014a970 0x087b8 0x087b8 RW  0x1000
      LOAD           0x151140 0x0000000000154140 0x0000000000154140 0x00f70 0x0eae8 RW  0x1000
      DYNAMIC        0x150d90 0x0000000000152d90 0x0000000000152d90 0x00120 0x00120 RW  0x8
      GNU_RELRO      0x148970 0x000000000014a970 0x000000000014a970 0x087b8 0x09690 R   0x1
      GNU_EH_FRAME   0x01c1b4 0x000000000001c1b4 0x000000000001c1b4 0x0633c 0x0633c R   0x4
      GNU_STACK      0x000000 0x0000000000000000 0x0000000000000000 0x00000 0x00000 RW  0
      NOTE           0x000270 0x0000000000000270 0x0000000000000270 0x00020 0x00020 R   0x4
    
     Section to Segment mapping:
      Segment Sections...
       00
       01     .note.gnu.build-id .dynsym .gnu.hash .dynstr .relr.dyn .rela.plt .rodata .gcc_except_table .eh_frame_hdr .eh_frame
       02     .text .iplt
       03     .data.rel.ro .init_array .dynamic .got .got.plt
       04     .data
       05     .dynamic
       06     .data.rel.ro .init_array .dynamic .got .got.plt
       07     .eh_frame_hdr
       08
       09     .note.gnu.build-id
      
    

    这里我们没有找到 INTERP 字段,按照这边文章 的说法,executable 是应当包含 INTERP 字段的,而 shared library 是不包含的,所以这理应是个 shared library ?所以才会有 SONAME.

    可是 shared library 是没法直接在 command line 中运行的,但是实际上又可以运行:

    x86_64:/apex/com.android.runtime/bin # ./linker64 --help
    Usage: ./linker64 [--list] PROGRAM [ARGS-FOR-PROGRAM...]
           ./linker64 [--list] path.zip!/PROGRAM [ARGS-FOR-PROGRAM...]
    
    A helper program for linking dynamic executables. Typically, the kernel loads
    this program because it's the PT_INTERP of a dynamic executable.
    
    This program can also be run directly to load and run a dynamic executable. The
    executable can be inside a zip file if it's stored uncompressed and at a
    page-aligned offset.
    
    The --list option gives behavior equivalent to ldd(1) on other systems.
    

    所以我迷糊了,是我理解产生了偏差了么。

    3 条回复    2024-01-29 15:54:34 +08:00
    codehz
        1
    codehz  
       304 天前
    常见 linux 发行版的 ld.so 也是可执行文件
    你猜 INTERP 这个词扩展开是啥(
    codehz
        2
    codehz  
       304 天前
    当然原则上 interpreter 可以 ET_EXEC 和 ET_DYN 里二选一即可,不过选 ET_EXEC 的话,会加载到固定地址上,可能会和实际可执行文件的地址冲突,ET_DYN 之后则可以允许在其他地址加载,没有规定 interpreter 在 ET_DYN 模式下是否可以是一个可执行文件,只要求不能递归指定 interpreter ,一般来说约定有 ET_DYN 没有 interpreter 表示它自身就是 interp ,可以参考内核里的注释
    /*
    * This logic is run once for the first LOAD Program
    * Header for ET_DYN binaries to calculate the
    * randomization (load_bias) for all the LOAD
    * Program Headers.
    *
    * There are effectively two types of ET_DYN
    * binaries: programs (i.e. PIE: ET_DYN with INTERP)
    * and loaders (ET_DYN without INTERP, since they
    * _are_ the ELF interpreter). The loaders must
    * be loaded away from programs since the program
    * may otherwise collide with the loader (especially
    * for ET_EXEC which does not have a randomized
    * position). For example to handle invocations of
    * "./ld.so someprog" to test out a new version of
    * the loader, the subsequent program that the
    * loader loads must avoid the loader itself, so
    * they cannot share the same load range. Sufficient
    * room for the brk must be allocated with the
    * loader as well, since brk must be available with
    * the loader.
    *
    * Therefore, programs are loaded offset from
    * ELF_ET_DYN_BASE and loaders are loaded into the
    * independently randomized mmap region (0 load_bias
    * without MAP_FIXED nor MAP_FIXED_NOREPLACE).
    */
    tool2d
        3
    tool2d  
       304 天前
    我按照说明,尝试了一下 https://bhushanverma.blogspot.com/2008/06/how-to-run-shared-library-on-linux.html

    提到两点,用 Position Independent Executables 编译(-PIE),和用(-Wl,-e entry_point)指定入口。

    可惜没成功。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5510 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 21ms · UTC 09:06 · PVG 17:06 · LAX 01:06 · JFK 04:06
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.