生产问题导致我们的团队提出以下问题:
ntohs
RHEL6下使用GCC 4.4.6 ,是如何ntohl
实现的?- 实施是快还是慢?
- 我如何才能真正看到为函数生成的汇编代码?
我知道问题背后的含义可能看起来牵强和荒谬,但我被要求进行调查。
有问题的硬件是一个英特尔盒子、小端、64 位处理器并以 64 位编译。
请执行下列操作:
#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)
提示:
12(%esp)
是 volatile 变量的地址。movl
说明都volatile
针对x
. 唯一真正有趣的指令是bswap
.ntohl
被编译为 inline-intrinsic。此外,如果我查看test.i
(预编译输出),我发现ntohl
is #defined
as simple __bswap_32()
,它是一个内联函数,只需调用__builtin_bswap32()
.
/usr/include/bits/byteswap.h
。)__bswap_16
__bswap_32
<netinet/in.h>
-save-temps
选项来保留中间.s
文件,或者使用-S
编译后和汇编代码之前停止,或者使用http://gcc.godbolt.org/这些在 glibc 中实现。查看/usr/include/netinet/in.h。他们很可能会依赖 glibc byteswap 宏(我机器上的 /usr/include/bits/byteswap.h)
这些是在我的标题中的汇编中实现的,所以应该很快。对于常量,这是在编译时完成的。
GCC/glibc 导致 ntohl() 和 htonl() 被内联到调用代码中。因此,避免了函数调用开销。此外,每个 ntohl() 或 htonl() 调用都被转换为单个 bswap 汇编器操作。根据“英特尔® 64 和 IA-32 架构优化参考手册”,bswap 在所有当前英特尔 CPU 上的延迟和吞吐量均为“1”。因此,执行 ntohl() 或 htonl() 只需要一个 CPU 时钟。
ntohs() 和 htons() 被实现为 8 位的旋转。这有效地交换了 16 位操作数的两半。延迟和吞吐量类似于 bswap。