请帮助理解来自 GLIBC_2.14 的以下 memcpy 代码
Please help to understand the following memcpy code from GLIBC_2.14
180688 000000000009f150 <memcpy@@GLIBC_2.14>:
180689 ¦9f150: 48 8b 0d 01 bd 34 00 mov 0x34bd01(%rip),%rcx # 3eae58 <_rtld_global_ro@GLIBC_PRIVATE>
180690 ¦9f157: 48 8d 05 d2 c3 01 00 lea 0x1c3d2(%rip),%rax # bb530 <memcpy@GLIBC_2.2.5+0x60>
180691 ¦9f15e: 8b 91 b4 00 00 00 mov 0xb4(%rcx),%edx
180692 ¦9f164: f7 c2 00 00 08 00 test [=11=]x80000,%edx
180693 ¦9f16a: 75 59 jne 9f1c5 <memcpy@@GLIBC_2.14+0x75>
180694 ¦9f16c: 89 d0 mov %edx,%eax
180695 ¦9f16e: 25 00 10 10 00 and [=11=]x101000,%eax
180696 ¦9f173: 3d 00 10 00 00 cmp [=11=]x1000,%eax
180697 ¦9f178: 74 56 je 9f1d0 <memcpy@@GLIBC_2.14+0x80>
180698 ¦9f17a: f6 c6 08 test [=11=]x8,%dh
180699 ¦9f17d: 0f 85 7d 00 00 00 jne 9f200 <memcpy@@GLIBC_2.14+0xb0>
180700 ¦9f183: f6 41 79 02 testb [=11=]x2,0x79(%rcx)
180701 ¦9f187: 74 08 je 9f191 <memcpy@@GLIBC_2.14+0x41>
180702 ¦9f189: f7 c2 00 00 04 00 test [=11=]x40000,%edx
180703 ¦9f18f: 74 1f je 9f1b0 <memcpy@@GLIBC_2.14+0x60>
180704 ¦9f191: f6 81 85 00 00 00 02 testb [=11=]x2,0x85(%rcx)
180705 ¦9f198: 48 8d 15 f1 c3 01 00 lea 0x1c3f1(%rip),%rdx # bb590 <memcpy@GLIBC_2.2.5+0xc0>
180706 ¦9f19f: 48 8d 05 2a c3 01 00 lea 0x1c32a(%rip),%rax # bb4d0 <memcpy@GLIBC_2.2.5>
180707 ¦9f1a6: 48 0f 45 c2 cmovne %rdx,%rax
180708 ¦9f1aa: c3 retq
180709 ¦9f1ab: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
180710 ¦9f1b0: 83 e2 02 and [=11=]x2,%edx
180711 ¦9f1b3: 48 8d 05 06 d8 0c 00 lea 0xcd806(%rip),%rax # 16c9c0 <__nss_group_lookup@GLIBC_2.2.5+0x2a10>
180712 ¦9f1ba: 48 8d 15 6f 2d 0d 00 lea 0xd2d6f(%rip),%rdx # 171f30 <__nss_group_lookup@GLIBC_2.2.5+0x7f80>
180713 ¦9f1c1: 48 0f 45 c2 cmovne %rdx,%rax
180714 ¦9f1c5: f3 c3 repz retq
180715 ¦9f1c7: 66 0f 1f 84 00 00 00 nopw 0x0(%rax,%rax,1)
180716 ¦9f1ce: 00 00
180717 ¦9f1d0: 81 e2 00 00 02 00 and [=11=]x20000,%edx
180718 ¦9f1d6: 48 8d 05 f3 34 0f 00 lea 0xf34f3(%rip),%rax # 1926d0 <__nss_group_lookup@GLIBC_2.2.5+0x28720>
180719 ¦9f1dd: 75 e6 jne 9f1c5 <memcpy@@GLIBC_2.14+0x75>
180720 ¦9f1df: f6 81 85 00 00 00 02 testb [=11=]x2,0x85(%rcx)
180721 ¦9f1e6: 48 8d 15 43 3f 0f 00 lea 0xf3f43(%rip),%rdx # 193130 <__nss_group_lookup@GLIBC_2.2.5+0x29180>
180722 ¦9f1ed: 48 8d 05 cc 3e 0f 00 lea 0xf3ecc(%rip),%rax # 1930c0 <__nss_group_lookup@GLIBC_2.2.5+0x29110>
180723 ¦9f1f4: 48 0f 45 c2 cmovne %rdx,%rax
180724 ¦9f1f8: c3 retq
180725 ¦9f1f9: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
180726 ¦9f200: f6 81 85 00 00 00 02 testb [=11=]x2,0x85(%rcx)
180727 ¦9f207: 48 8d 15 32 fb 0e 00 lea 0xefb32(%rip),%rdx # 18ed40 <__nss_group_lookup@GLIBC_2.2.5+0x24d90>
180728 ¦9f20e: 48 8d 05 cb fa 0e 00 lea 0xefacb(%rip),%rax # 18ece0 <__nss_group_lookup@GLIBC_2.2.5+0x24d30>
180729 ¦9f215: 48 0f 45 c2 cmovne %rdx,%rax
180730 ¦9f219: c3 retq
180731 ¦9f21a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
以上代码由objdump应用转储。我有以下问题。
- 我找不到实际的复制代码。例如,在 memcpy@@GLIBC_3.XX 中,我们可以看到:
movups xmm0, ptr qword[rsi]
movups ptr qword[rdi], xmm0
但是在这个函数中,我们看不到这种先读后写的代码。它是如何进行复制操作的?
这看起来像 glibc 的动态链接解析器函数 returns 一个基于 CPUID 的函数指针(在 %rax
中),例如在 CPU 上选择支持它的 AVX 版本。
此解析器覆盖在动态链接期间运行一次(例如,如果您使用 lazy 动态链接,则在第一次调用时)。
是的,这是您将在符号名称 memcpy
处找到的代码。
相关: 讨论了那个 memset 实现,通用调度程序在那个提问者的 CPU 上选择了它。
请注意,glibc 是开源的,您可以查看 hand-written commented asm 源代码,例如其 memcpy / memmove 实现,例如https://code.woboq.org/userspace/glibc/sysdeps/x86_64/multiarch/memmove-avx-unaligned-erms.S.html
180688 000000000009f150 <memcpy@@GLIBC_2.14>:
180689 ¦9f150: 48 8b 0d 01 bd 34 00 mov 0x34bd01(%rip),%rcx # 3eae58 <_rtld_global_ro@GLIBC_PRIVATE>
180690 ¦9f157: 48 8d 05 d2 c3 01 00 lea 0x1c3d2(%rip),%rax # bb530 <memcpy@GLIBC_2.2.5+0x60>
180691 ¦9f15e: 8b 91 b4 00 00 00 mov 0xb4(%rcx),%edx
180692 ¦9f164: f7 c2 00 00 08 00 test [=11=]x80000,%edx
180693 ¦9f16a: 75 59 jne 9f1c5 <memcpy@@GLIBC_2.14+0x75>
180694 ¦9f16c: 89 d0 mov %edx,%eax
180695 ¦9f16e: 25 00 10 10 00 and [=11=]x101000,%eax
180696 ¦9f173: 3d 00 10 00 00 cmp [=11=]x1000,%eax
180697 ¦9f178: 74 56 je 9f1d0 <memcpy@@GLIBC_2.14+0x80>
180698 ¦9f17a: f6 c6 08 test [=11=]x8,%dh
180699 ¦9f17d: 0f 85 7d 00 00 00 jne 9f200 <memcpy@@GLIBC_2.14+0xb0>
180700 ¦9f183: f6 41 79 02 testb [=11=]x2,0x79(%rcx)
180701 ¦9f187: 74 08 je 9f191 <memcpy@@GLIBC_2.14+0x41>
180702 ¦9f189: f7 c2 00 00 04 00 test [=11=]x40000,%edx
180703 ¦9f18f: 74 1f je 9f1b0 <memcpy@@GLIBC_2.14+0x60>
180704 ¦9f191: f6 81 85 00 00 00 02 testb [=11=]x2,0x85(%rcx)
180705 ¦9f198: 48 8d 15 f1 c3 01 00 lea 0x1c3f1(%rip),%rdx # bb590 <memcpy@GLIBC_2.2.5+0xc0>
180706 ¦9f19f: 48 8d 05 2a c3 01 00 lea 0x1c32a(%rip),%rax # bb4d0 <memcpy@GLIBC_2.2.5>
180707 ¦9f1a6: 48 0f 45 c2 cmovne %rdx,%rax
180708 ¦9f1aa: c3 retq
180709 ¦9f1ab: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
180710 ¦9f1b0: 83 e2 02 and [=11=]x2,%edx
180711 ¦9f1b3: 48 8d 05 06 d8 0c 00 lea 0xcd806(%rip),%rax # 16c9c0 <__nss_group_lookup@GLIBC_2.2.5+0x2a10>
180712 ¦9f1ba: 48 8d 15 6f 2d 0d 00 lea 0xd2d6f(%rip),%rdx # 171f30 <__nss_group_lookup@GLIBC_2.2.5+0x7f80>
180713 ¦9f1c1: 48 0f 45 c2 cmovne %rdx,%rax
180714 ¦9f1c5: f3 c3 repz retq
180715 ¦9f1c7: 66 0f 1f 84 00 00 00 nopw 0x0(%rax,%rax,1)
180716 ¦9f1ce: 00 00
180717 ¦9f1d0: 81 e2 00 00 02 00 and [=11=]x20000,%edx
180718 ¦9f1d6: 48 8d 05 f3 34 0f 00 lea 0xf34f3(%rip),%rax # 1926d0 <__nss_group_lookup@GLIBC_2.2.5+0x28720>
180719 ¦9f1dd: 75 e6 jne 9f1c5 <memcpy@@GLIBC_2.14+0x75>
180720 ¦9f1df: f6 81 85 00 00 00 02 testb [=11=]x2,0x85(%rcx)
180721 ¦9f1e6: 48 8d 15 43 3f 0f 00 lea 0xf3f43(%rip),%rdx # 193130 <__nss_group_lookup@GLIBC_2.2.5+0x29180>
180722 ¦9f1ed: 48 8d 05 cc 3e 0f 00 lea 0xf3ecc(%rip),%rax # 1930c0 <__nss_group_lookup@GLIBC_2.2.5+0x29110>
180723 ¦9f1f4: 48 0f 45 c2 cmovne %rdx,%rax
180724 ¦9f1f8: c3 retq
180725 ¦9f1f9: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
180726 ¦9f200: f6 81 85 00 00 00 02 testb [=11=]x2,0x85(%rcx)
180727 ¦9f207: 48 8d 15 32 fb 0e 00 lea 0xefb32(%rip),%rdx # 18ed40 <__nss_group_lookup@GLIBC_2.2.5+0x24d90>
180728 ¦9f20e: 48 8d 05 cb fa 0e 00 lea 0xefacb(%rip),%rax # 18ece0 <__nss_group_lookup@GLIBC_2.2.5+0x24d30>
180729 ¦9f215: 48 0f 45 c2 cmovne %rdx,%rax
180730 ¦9f219: c3 retq
180731 ¦9f21a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
以上代码由objdump应用转储。我有以下问题。
- 我找不到实际的复制代码。例如,在 memcpy@@GLIBC_3.XX 中,我们可以看到:
但是在这个函数中,我们看不到这种先读后写的代码。它是如何进行复制操作的?movups xmm0, ptr qword[rsi] movups ptr qword[rdi], xmm0
这看起来像 glibc 的动态链接解析器函数 returns 一个基于 CPUID 的函数指针(在 %rax
中),例如在 CPU 上选择支持它的 AVX 版本。
此解析器覆盖在动态链接期间运行一次(例如,如果您使用 lazy 动态链接,则在第一次调用时)。
是的,这是您将在符号名称 memcpy
处找到的代码。
相关:
请注意,glibc 是开源的,您可以查看 hand-written commented asm 源代码,例如其 memcpy / memmove 实现,例如https://code.woboq.org/userspace/glibc/sysdeps/x86_64/multiarch/memmove-avx-unaligned-erms.S.html