• Windows内核--内核汇编代码赏析: Rtl memory系列函数(3.3.1)


    找不到memcpy源代码?

            RtlXXXMemory宏和mem* 

                    

            搜索WRK源代码,找不到memxxx相关函数的源代码。它们在如下prebuilt lib库中。      

                    

            IDA工具查找ntoswrk.lib里memxxx函数的实现如下:

                    

    先从memchr开始      

    1. ; amd64 assemble
    2. .text:00000000004A51D0 ; void *__cdecl memchr(const void *Buf, int Val, size_t MaxCount)
    3. .text:00000000004A51D0 public memchr
    4. .text:00000000004A51D0 memchr proc near
    5. .text:00000000004A51D0 test r8, r8
    6. .text:00000000004A51D3 jz short loc_4A51E1
    7. .text:00000000004A51D5
    8. .text:00000000004A51D5 loc_4A51D5: ; CODE XREF: memchr+F↓j
    9. .text:00000000004A51D5 cmp [rcx], dl
    10. .text:00000000004A51D7 jz short loc_4A51E1
    11. .text:00000000004A51D9 inc rcx
    12. .text:00000000004A51DC dec r8
    13. .text:00000000004A51DF jnz short loc_4A51D5
    14. .text:00000000004A51E1
    15. .text:00000000004A51E1 loc_4A51E1: ; CODE XREF: memchr+3↑j
    16. .text:00000000004A51E1 ; memchr+7↑j
    17. .text:00000000004A51E1 xor eax, eax
    18. .text:00000000004A51E3 test r8, r8
    19. .text:00000000004A51E6 cmovnz rax, rcx
    20. .text:00000000004A51EA retn
    21. .text:00000000004A51EA memchr endp

            a. 为何出现r8/rcx/dl寄存器操作?

                    如上为amd64架构汇编,amd64 calling conversion默认函数前四个参数以rcx, rdx, r8 and r9传入。

    Bufrcx
    Valrdx
    MaxCountr8

            b. 汇编flow: test r8, r8判断r8, 如果是0:

                                                    跳到最后,eax清成0,再次判断r8是否是0,不为0,把rcx(Buf指针)赋值给rax, rax作为返回值返回。

                                            不是0:

                                                    比较*Buf和Val的低八位(以Byte单位),如相同,即找到字符位置,跳到最后返回,如不相同,Buf++, MacCount--, 重复开始的比较。

                                    

           工具生成 pseudo code

    1. void *__cdecl memchr(const void *Buf, int Val, size_t MaxCount)
    2. {
    3. void *result; // rax
    4. for ( ; MaxCount; --MaxCount )
    5. {
    6. if ( *(_BYTE *)Buf == (_BYTE)Val )
    7. break;
    8. Buf = (char *)Buf + 1;
    9. }
    10. result = 0i64; // 此处是工具解析的问题,可以先忽略
    11. if ( MaxCount )
    12. result = (void *)Buf;
    13. return result;
    14. }

          memchr没有什么特别的。

    memset

            常规意义上,memset会按byte去写,这样没有充分利用64bit硬件的单个指令高效性。

                    工具生成pseudo code:

                    ​​​​​​​        

                            首先判断是否超过8B, 超过就会优先按8B为单位去写。这里利用了 Val * 0x0101010101010101巧妙一次填充8个Val.

                                  eg:   ​​​​​​​

     memcpy

            为了尽可能减少以8字节为单位不断从内存(或CacheLine)中抓数据,内核实作优先采用更大的单位。

            32B:

                    

            4KB:

                    

                    prefetchnta指令可以实现跨页边界存取,非常强大。内核可能存在超过4KB数据量copy, 此指令相比常规的register大小为单位可以大幅提高性能。

             

  • 相关阅读:
    java 手写KMP算法
    【Leetcode刷题Python】5. 最长回文子串
    一个基与邮件的数据下载存储系统
    NFV关键技术:DPDK技术栈在网络云中的最佳实践
    一行Python代码即可实现数据可视化大屏
    【LeetCode】2578. 最小和分割
    ubuntu16.04 安装搜狗输入法
    1.4 TCP/IP网络协议
    如何读取resources目录下的文件路径(九种方式)
    腾讯视频跟爱奇艺视频共享设备ip会不会出现错误
  • 原文地址:https://blog.csdn.net/cxsjabcabc/article/details/127797351