【问题标题】:How are the ntoh functions implemented under RHEL/GCC?RHEL/GCC下的ntoh函数是如何实现的?
【发布时间】:2013-07-30 23:23:20
【问题描述】:

生产问题导致我们的团队提出以下问题:

  1. 在使用 GCC 4.4.6 的 RHEL6 下,ntohsntohl 是如何实现的?
  2. 已知的实现是快还是慢?
  3. 我如何才能真正看到为函数生成的汇编代码?

我知道问题背后的含义可能看起来牵强和荒谬,但我被要求进行调查。

所讨论的硬件是一个 Intel 机器、小端序、64 位处理器并以 64 位编译。

【问题讨论】:

  • GCC.4.4 是一个非常老的 GCC 版本。当前一个是4.8.1。您应该考虑升级您的编译器(请注意,自 GCC 4.4 以来,C++ 支持有了很大改进)
  • @Basile,4.4是RHEL6上的系统编译器,得到支持和维护,坚持下去也不是没有道理
  • @BasileStarynkevitch:确实,我使用 GCC 4.7.2 和 4.8.1 进行大多数开发和研发类型的工作,但我们将 4.4 用于生产代码,因为这是随发行版分发的内容。跨度>
  • @Charles:我认为 RHEL6 标签在这种情况下是相关的。为什么要删除它?
  • @JohnDibling,给出答案,我实际上建议使用 glibc 进行标记,而不是为 RHEL 6 创建标记,因为这些功能由 glibc 提供,而不是操作系统本身。跨度>

标签: c++ linux gcc glibc gcc4.4


【解决方案1】:

执行以下操作:

test.c

#include <arpa/inet.h>
int main()
{
   volatile uint32_t x = 0x12345678;
   x = ntohl(x);
   return 0;
}

然后编译:

$ gcc -O3 -g -save-temps test.c

并分析生成的test.s 文件,或者运行objdump -S test.o

在我的机器(Ubuntu 13.4)中,相关的汇编器是:

movl    $305419896, 12(%esp)
movl    12(%esp), %eax
bswap   %eax
movl    %eax, 12(%esp)

提示:

  • 305419896 是十进制的 0x12345678。
  • 12(%esp) 是 volatile 变量的地址。
  • 所有的movl 指令都是针对volatilex 的。唯一真正有趣的指令是bswap
  • 很明显,ntohl 被编译为 inline-intrinsic。

此外,如果我查看test.i(预编译输出),我发现ntohl 就是#defined,就像__bswap_32(),它是一个内联函数,只需调用__builtin_bswap32()

【讨论】:

  • 谢谢。这非常有帮助。
  • +1。另请注意,如果没有volatile,GCC 将传播常量并在编译时交换它(glibc 实现使用builtin_constant_p 来实现这一点)。所以这个问题的简短回答是“它是零个或一个指令,所以你可以忽略它”。早在 RHEL 6 之前,这就是事实。
【解决方案2】:
  1. 它们由 glibc 而非 GCC 提供,在 /usr/include/bits/byteswap.h 中查找 __bswap_16__bswap_32 函数,它们在启用优化时使用(有关如何使用的详细信息,请参阅 &lt;netinet/in.h&gt;。)
  2. 您没有说您使用的是什么架构,在大端系统上它们是无操作的,所以速度非常快!在 little-endian 上,它们是特定于架构的手动优化汇编代码。
  3. 使用 GCC 的-save-temps 选项保留中间的.s 文件,或者使用-S 在编译之后和汇编代码之前停止,或者使用http://gcc.godbolt.org/

【讨论】:

  • 抱歉,完全正确。这是一台 x86_64 机器,所以小端。
【解决方案3】:

这些都是在 glibc 中实现的。查看/usr/include/netinet/in.h。他们很可能会依赖 glibc byteswap 宏(我机器上的 /usr/include/bits/byteswap.h)

这些是在我的标题中的汇编中实现的,所以应该很快。对于常量,这是在编译时完成的。

【讨论】:

    【解决方案4】:

    GCC/glibc 导致 ntohl() 和 htonl() 内联到调用代码中。因此,避免了函数调用开销。此外,每个 ntohl() 或 htonl() 调用都被转换为单个 bswap 汇编器操作。根据“英特尔® 64 和 IA-32 架构优化参考手册”,bswap 在所有当前英特尔 CPU 上的延迟和吞吐量均为“1”。因此,执行 ntohl() 或 htonl() 只需要一个 CPU 时钟。

    ntohs() 和 htons() 实现为 8 位旋转。这有效地交换了 16 位操作数的两半。延迟和吞吐量与 bswap 类似。

    【讨论】:

      猜你喜欢
      • 2012-09-04
      • 1970-01-01
      • 2015-06-02
      • 2014-02-06
      • 2021-01-10
      • 1970-01-01
      • 2012-01-18
      • 2014-03-26
      相关资源
      最近更新 更多