编译一个静态二进制文件,编码函数gethostbyname

时间:2013-03-01 19:24:55

标签: c++ c linux gcc gethostbyname

如何解析编译一个静态二进制文件,其代码包含一个函数gethostbyname,如果编译时没有像这样的警告:

  

警告:在静态链接的应用程序中使用“gethostbyname”   在运行时需要使用glibc版本的共享库   用于链接

我使用命令:

在ubuntu 12.04上编译
$ gcc -static lookup.c -o lookup

这是lookup.c的代码:

  /* lookup.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;
  }

如果我通过$ file lookup检查,我想得到如下输出:

  

查找:ELF 32位LSB可执行文件,Intel 80386,版本1(GNU / Linux),   静态链接,对于GNU / Linux 2.6.24,   BuildID [sha1] = 0x6fcb2684ad8e5e842036936abb50911cdde47c73,未剥离

不喜欢这样:

  

查找:ELF 32位LSB可执行文件,Intel 80386,版本1(SYSV),   动态链接(使用共享库),用于GNU / Linux 2.6.24,   BuildID [sha1] = 0xf9f18671751927bea80de676d207664abfdcf5dc,未剥离

如果您评论了建议我必须使用不带静态,因为我知道每个linux不同的libc,我希望你不需要评论。 为什么我坚持静态? 因为我需要强制使用静态,所以二进制文件必须是静态的而不是动态的。

我有超过2周的时间来寻找这个,但到目前为止还没有成功。

感谢您帮助我解决我的沉重问题。

3 个答案:

答案 0 :(得分:26)

你所要求的将是非常困难的。

this StackOverflow question about getaddrinfo。基本上,getaddrinfo / gethostbyname下面是glibc的NSS层。这允许系统管理员说&#34;使用DNS将主机名解析为IP地址&#34;或&#34;使用LDAP&#34;或者不使用除{{1}以外的任何内容}}&#34 ;.该控件在运行时;系统管理员可以随时改变主机名解析为IP的方式。

由于这种灵活性,glibc中的所有名称解析调用都使用帮助程序库(基本上是插件)来执行解决方案的繁重工作。有一个用于LDAP寻址的共享库,一个用于文件,一个用于DNS,一个用于YP,依此类推。

如果您希望程序100%静态链接,那么您将不得不转到其他地方(不是/etc/hosts)将主机名转换为IP地址。您可以使用像uDNS这样的解析程序库来执行此操作(不是这一个 - 有类似的工具可用),但您应该记住您的二进制文件不会在系统上做正确的事情配置为不使用DNS

相反,我建议只是让程序(技术上)动态链接。如果你真的想确保它可以在任何平台上运行,你甚至可以使用二进制文件发送gethostbyname - 尽管这样做需要LGPL一致性。保留这一动态链接只会意味着您不会使用错误的glibc版本的系统工作 - 而不是一个巨大的兼容性问题。

说到许可证合规性,值得注意的是,如果您静态链接glibc,则很可能必须提供整个应用程序的源代码才能符合{ {1}}的LGPL许可证。我不是律师,这不是合格的法律建议,但阅读LGPL非常清楚,静态链接glibc的应用程序必须是开源的。请参阅this StackOverflow question on the topic

答案 1 :(得分:6)

我收到同样的警告并修复它我重新编译了glibc。在配置时打开开关--enable-static-nss以使其工作。

答案 2 :(得分:0)

我有2个答案 -

  1. 保持程序的主要部分静态链接,并将单个函数程序分开以调用gethostbyname()。允许后者动态链接。使用fork然后exec执行这个单独的程序来获取域名的地址。而不是fork然后执行你可以使用system(),虽然它需要更长的时间(一整毫秒),因为你无论如何都在互联网上搜索名称服务器,这需要花费一些时间。

  2. 编写源代码以执行DNS,就像我所做的那样。将其编译为存档(.a)并在静态链接中进行搜索。