【问题标题】:Linking with versioned shared library in Android NDK与 Android NDK 中的版本化共享库链接
【发布时间】:2012-07-14 12:27:19
【问题描述】:

我正在尝试通过 loadLibrary 调用在我的 Android 应用程序中加载两个共享库:

System.loadLibrary("mywrapper");
System.loadLibrary("crypto");

我一直在运行,捕获 `UnsatisfiedLinkError。这是错误的更详细版本。

Caused by: java.lang.UnsatisfiedLinkError: Cannot load library: link_image[1969]:
  130 could not load needed library 'libcrypto.so.1.0.0' for 
  'libmywrapper.so' (load_library[1111]: Library 'libcrypto.so.1.0.0' not found)

有什么想法吗?

花了一些时间后,我发现 Android 不支持版本库。有没有人遇到过同样的问题?

【问题讨论】:

    标签: android android-ndk shared-libraries


    【解决方案1】:

    我在为 Android 构建 libwebsockets 时遇到了同样的问题,它需要与 OpenSSL 链接。我以 libssl.so 为例。您应该对相关的 .so 文件执行相同的操作。

    Before:
    huiying@huiying-PORTEGE-R835:~$ objdump -p libssl.so | grep so
    libssl.so:     file format elf32-little
      NEEDED               libcrypto.so.1.0.0
      NEEDED               libdl.so
      NEEDED               libc.so
      SONAME               libssl.so.1.0.0
    
    After 
    huiying@huiying-PORTEGE-R835:~$ rpl -R -e .so.1.0.0 "_1_0_0.so" libssl.so 
    Replacing ".so.1.0.0" with "_1_0_0.so" (case sensitive) (partial words matched)
    .
    A Total of 2 matches replaced in 1 file searched.
    huiying@huiying-PORTEGE-R835:~$ objdump -p libssl.so | grep so
    libssl.so:     file format elf32-little
      NEEDED               libcrypto_1_0_0.so
      NEEDED               libdl.so
      NEEDED               libc.so
      SONAME               libssl_1_0_0.so
    
    And don't forget to change file name "libssl.so" to "libssl_1_0_0.so".

    破解有效。我已经运行 Android 应用程序来证明这一点。在http://computervisionandjava.blogspot.com/2015/05/trouble-with-versioned-shared-libraries.html 看到我的咆哮。

    【讨论】:

    • 我无法让 rpl 使用 .so 文件,但我能够使用 VIM 编辑文件并在那里进行字符串替换。伟大的黑客。谢谢!
    【解决方案2】:

    似乎 android 在加载版本化库时存在问题。手头的问题是因为库名称在我的情况下为 libcrypto.so.1.0.0。即使您重命名库并尝试将其作为预构建的共享库加载到 android make 文件中,它也会失败。(这一定是因为库名称以某种方式嵌入在文件中。任何与它链接的库都希望是与同名的库链接)

    我希望在 android 中处理带有版本名称的库时还有其他方法。

    现在我通过使用 openssl 的静态库并将它们与我自己的共享库链接在一起来避免这个问题。

    【讨论】:

      【解决方案3】:

      2014 年,仍然不支持版本化共享库。所以我做了一个脚本来修补 SONAME。只需将脚本指向放置所有版本化库的输入目录即可。然后检查输出目录“unver”。

      #!/bin/bash
      
      DIR="$1"
      
      if [ "$DIR" == "" ]; then
          echo "Usage: fix-soname.sh <target dir>"
          exit
      fi
      
      if [ ! -d $DIR ]; then
          echo "Not found: $DIR"
          exit
      fi
      
      OUT="$DIR/unver"
      echo "Input=$DIR"
      echo "Output=$OUT"
      
      CWD=$(pwd)
      cd $DIR
      
      # prep dirs
      mkdir -p $OUT
      rm -f -R $OUT/*
      
      # rename libs and copy to out dir
      find "$DIR" -type f -name '*.so*' | while read FILE; do
      
          NAME=$(basename "$FILE")
          SONAME=$NAME
      
          while read SYMLINK; do
              X=$(basename "$SYMLINK")
              #echo "$X (${#X}) -> $NAME (${#NAME})"
              if [ "${#X}" -lt "${#SONAME}" ]; then
                  SONAME=$X
              fi
      done<<EOT
      `find -L $DIR -samefile $FILE`
      EOT
      
          #echo $SONAME
          cp -f $SONAME $OUT/
      done
      
      # patch libs in out dir
      find "$OUT" -type f -name '*.so*' | while read FILE; do
      
          # get file name without path
          NAME=$(basename "$FILE")
      
          # extract SONAME from shared lib
          SONAME=`readelf -d $FILE | grep '(SONAME)' | grep -P '(?<=\[)(lib.*?)(?=\])' -o`
      
          #echo "$NAME [$SONAME]"
      
          # patch SONAME if required
          if [ "$NAME" != "$SONAME" ]; then
              L1=${#NAME}
              L2=${#SONAME}
              LDIFF=$((L2-L1))
              #echo "$NAME [$SONAME] ($LDIFF)"
      
              if [ "$LDIFF" -gt "0" ]; then
                  SONEW=$NAME
                  for (( c=1; c<=$LDIFF; c++ )); do
                      SONEW+="\x00"
                  done
                  echo "$NAME [$SONAME] -> $SONEW ($LDIFF)"
                  rpl -R -e "$SONAME" "$SONEW" $OUT
              fi
          fi
      done
      
      cd $CWD
      

      【讨论】:

      • 它对我不起作用...我在 openssl 源目录上运行它,编译了二进制文件,并且“unver”目录输出与原始二进制 libcrypto.so 完全相同
      • 您可以在脚本中取消注释#echo,看看哪里出了问题。
      猜你喜欢
      • 1970-01-01
      • 2015-04-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多