6

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

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

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

有问题的硬件是一个英特尔盒子、小端、64 位处理器并以 64 位编译。

4

4 回答 4

12

请执行下列操作:

测试.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说明都volatile针对x. 唯一真正有趣的指令是bswap.
  • 显然,ntohl被编译为 inline-intrinsic。

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

于 2013-07-30T17:25:27.090 回答
11
  1. 它们是由 glibc 提供的,而不是 GCC,查找和函数,这些函数在启用优化时使用(有关如何使用的详细信息,请参阅/usr/include/bits/byteswap.h。)__bswap_16__bswap_32<netinet/in.h>
  2. 你没有说你正在使用什么架构,在大端系统上它们是无操作的,所以速度非常快!在 little-endian 上,它们是特定于架构的手动优化汇编代码。
  3. 使用 GCC 的-save-temps选项来保留中间.s文件,或者使用-S编译后和汇编代码之前停止,或者使用http://gcc.godbolt.org/
于 2013-07-30T17:26:20.790 回答
7

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

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

于 2013-07-30T17:24:45.073 回答
1

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

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

于 2013-08-11T13:32:48.643 回答