【问题标题】:Compile C with function gethostbyname to static linked error使用函数 gethostbyname 将 C 编译为静态链接错误
【发布时间】:2013-02-27 17:28:55
【问题描述】:

我正在尝试使用函数gethostbyname() 和交叉编译器arm-none-linux-gnueabi 编译程序,但是当我在android 上运行我的二进制文件时它不起作用。

我的代码如下:

  /* gethostbyname-example.c */

  #include <stdio.h>
  #include <unistd.h>
  #include <stdlib.h>
  #include <string.h>
  #include <errno.h>
  #include <sys/socket.h>
  #include <netinet/in.h>
  #include <arpa/inet.h>
  #include <netdb.h>

  extern int h_errno;

  int main(int argc,char **argv) {
     int x, x2;
     struct hostent *hp;

     for ( x=1; x<argc; ++x ) {
        hp = gethostbyname(argv[x]);
        if ( !hp ) {
           fprintf(stderr,
                   "%s: host '%s'\n",
                   hstrerror(h_errno),
                   argv[x]);
           continue;
        }

        printf("Host %s : \n" ,argv[x]);
        printf(" Officially:\t%s\n", hp->h_name);
        fputs(" Aliases:\t",stdout);
        for ( x2=0; hp->h_aliases[x2]; ++x2 ) {
           if ( x2 ) {
              fputs(", ",stdout);
             }
        fputs(hp->h_aliases[x2],stdout);
        }     
        fputc('\n',stdout);
        printf(" Type:\t\t%s\n",
               hp->h_addrtype == AF_INET
               ? "AF_INET" : "AF_INET6");
        if ( hp->h_addrtype == AF_INET ) {
           for ( x2=0; hp->h_addr_list[x2]; ++x2 ) {
              printf(" Address:\t%s\n",
                     inet_ntoa( *(struct in_addr *)
                      hp->h_addr_list[x2]));
           }
        }
     putchar('\n');
     }
     return 0;
  }

我使用arm-none-linux-gnueabi-gcc 编译,在我的笔记本电脑上使用操作系统ubuntu 12.04 和交叉编译器Sourcery Codebench:

$ arm-none-linux-gnueabi-gcc gethostbyname-example.c --static -o gethostbyname-example
/tmp/ccE0xjBG.o: In function `main':
lookup.c:(.text+0x38): warning: Using 'gethostbyname' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
$ ls
gethostbyname-example.c gethostbyname-example
$ file gethostbyname-example
gethostbyname-example: ELF 32-bit LSB executable, ARM, version 1 (SYSV), statically linked, for GNU/Linux 2.6.16, not stripped

然后我在我的 chroot 手臂上测试二进制文件 gethostbyname-example,我将二进制文件复制粘贴到 chroot 文件夹,然后我登录到 chroot,然后我执行,顺便说一句,我从这里创建 chroot https://wiki.ubuntu.com/ARM/BuildEABIChroot ,如果我在 chroot 上运行它,我会得到如下结果:

# ./gethostbyname-example www.google.com
Host google.com : 
 Officially:    www.google.com
 Aliases:   
 Type:      AF_INET
 Address:   74.125.135.139
 Address:   74.125.135.100
 Address:   74.125.135.101
 Address:   74.125.135.102
 Address:   74.125.135.113
 Address:   74.125.135.138

然后,我还将使用 adb push 的二进制 gethostbyname-example 上传到我的 android 设备,如果我运行二进制 gethostbyname-example,我会收到如下错误:

# ./gethostbyname-example www.google.com
# Unknown server error: host 'www.google.com'
# ping www.google.com
# PING www.google.com (74.125.135.99) 56(84) bytes of data.
# 64 bytes from ni-in-f99.1e100.net (74.125.135.99): icmp_seq=1 ttl=49 time=798 ms
# 64 bytes from ni-in-f99.1e100.net (74.125.135.99): icmp_seq=2 ttl=49 time=1039 ms

在我的 android 设备中,我在 /etc/ 和 /system/etc/ 中有一个文件 hosts,带有 google DNS

8.8.8.8 
8.8.4.4

大概是什么原因导致这个失败,

谢谢。

【问题讨论】:

  • 在 chroot 中运行的 arm 设备是什么类型的设备?听起来您正在链接到 glibc,其运行时可在您的 arm 设备上使用。在 android 上,没有 glibc。
  • 我在这里使用 chroot wiki.ubuntu.com/ARM/BuildEABIChroot
  • 所以它基本上是 Ubuntu 的 arm 版本,而不是 Android 之类的东西?

标签: android c cross-compiling compiler-warnings


【解决方案1】:

简短说明

glibc 中的 DNS 查找需要 /lib/libnss_dns.so.2 ,这在 Android 上不可用。

另一个区别是 Android 存储了 DNS 设置 /system/etc/resolv.conf ,而使用仿生 C 库构建的原生 Android 应用程序将在那里查找要查询的 DNS 服务器。使用 glibc 构建的应用程序将在 /etc/resolv.conf 中查找,而这在 Android 上不存在。

更长的解释

您已经使用 glibc 构建了二进制文件,而 Android 使用了仿生 C 库。

当静态链接到 libc 时,这在大多数情况下应该没问题,因为我不知道 android 内核中有足够严重的变化来破坏简单的用户空间应用程序。不过,您应该使用 Android NDK 来构建 Android 原生应用程序,

然而,当静态链接到 glibc 时,会出现一些问题。 glibc 中的某些函数,例如用于查找用户信息、主机名和通常在 /etc/nsswitch.conf 中配置的其他内容,调用其他共享库来实际完成工作。无论您是否静态链接到 glibc 本身,都会发生这种情况。这些文件通常是 glibc 系统上的 /lib/libnss_* 文件。

这些共享库中的大多数都是 glibc 的一部分,并且会安装在 glibc 系统上。但它们在 Android 上不可用。当这些共享库可用时,依赖于使用这些辅助共享库的函数的应用程序无法正常工作 - gethostbyname() 就是其中之一,对于正常的 DNS 查询,它需要 /lib/libnss_dns.so.2

【讨论】:

  • 您好,是否有解决方案,请给我详细的解决方案,谢谢。
  • @LorenRamly 解决方案是安装 Android NDK 并使用它为 Android 编译原生应用程序。
  • 除了使用仿生还有其他方法吗?我必须使用 glibc 使用 arm-none-linux-gnueabi,会在 arm-none-linux-gnueabi 上的 glibc 补丁中吗?谢谢
  • 因为上面的代码只是示例,但我想编译其他包含很多头文件 C 的软件。示例编译 lighttpd。
【解决方案2】:

解释参考没有回复,解决方法如下:

  • 从这里下载android NDK:https://developer.android.com/ndk/downloads/index.html(我用的是linux 64bit)
  • 解压android-ndk-r13b-linux-x86_64.zip
  • 进入刚刚解压的目录
  • 启动 ./build/tools/make_standalone_toolchain.py 以查看可能的选项
  • 例如./build/tools/make_standalone_toolchain.py --arch arm --api 9
  • 该工具将为您构建 arm-linux-androideabi.tar.bz2
  • 用 tar xjvf arm-linux-androideabi.tar.bz2 解压
  • 它将创建 ./arm-linux-androideabi 目录
  • 现在您可以使用 ./arm-linux-androideabi/bin/arm-linux-androideabi-gcc yourprog.c -o yourprog -pie 进行编译
  • -pie 需要 Android >= 5
  • 您生成的可执行文件是本机的,解析器将按预期工作

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多