【问题标题】:implementing memset in assembly x86在汇编 x86 中实现 memset
【发布时间】:2013-12-18 07:41:48
【问题描述】:

我正在尝试在程序集 x86 中实现 memset。都按字节和按字复制,所以我会得到两个函数:kmemsetkmemsetw,我以这种方式向我的 C 代码公开:

extern uint8_t* kmemset(uint8_t* dest, uint8_t val, uint8_t size);  
extern uint16_t* kmemsetw(uint16_t* dest, uint16_t val, uint8_t size);  

问题是当我测试它时,我遇到了分段错误。我尝试使用 gdb 进行调试,但似乎无法进入 asm 代码。如果有人可以对代码发表评论,我会很高兴。 (kmemset 非常相似,所以我没有包含它)。

.intel_syntax noprefix  
.section .text  
.align 16  
.global kmemsetw  
.type kmemsetw, @function  

kmemsetw:  
    push ebp  
    mov ebp, esp  
    push edi  
    push ecx  
    push ebx  
    xor eax, eax  
    mov ebx, [ebp+4]  
    mov ax, [ebp+8]  
    mov ecx, [ebp+12]  
    mov edi, ebx  
    rep stosw  
    mov eax, edi  
    pop ebx  
    pop ecx  
    pop edi  
    pop ebp  
    ret  

【问题讨论】:

  • 收到的长度参数是字节还是字?
  • 顺便说一句,还有stosd(双字大小的商店)。
  • 感谢您的提示。此外,长度参数作为字节 (uint8_t) 传递,但现在将其更改为双字 (uint32_t)。

标签: assembly x86 segmentation-fault


【解决方案1】:

您的参数引用位置偏离 4。如果您在函数序言中推送 ebp,然后更新 epb,则函数 ebp 之后的前两个(4 字节)位置将包含 ebp (SFP) 和 ret。您的代码使 ret 成为字符串副本的目标位置。将 4 添加到所有引用。

您如何传递/引用参数也可能存在问题,但这在代码 sn-p 中并不清楚。

编辑:这不是您的段错误,但您还需要更改返回方式。 edi 在 rep 存储期间更新,因此要返回指向内存区域开头的指针,请从临时存储它的 ebx 中获取它。

【讨论】:

    【解决方案2】:

    你没有在你的程序中使用ebx,为什么要保存它?它不需要保存。 ecx 是一个易失性寄存器,不需要保存。

    正如提到的 gnometorule,您的 proc 中的参数已关闭。

    另一个大问题是你没有在最后恢复堆栈指针。当然你pop ebp,但是你在哪里mov esp, ebp???你在开头mov ebp, esp,但永远不要反转它。

    如果您查看memset,它会返回传递给proc 的指针。所以,这是错误的: mov eax, edi 应该是:mov eax, [ebp + 8]rep stos? 增加了edi 中的指针,所以如果你返回edi,则返回的指针是错误的。

    但是为什么还要为这个小进程设置一个堆栈框架呢?使用esp即可,因为我们需要将edi保存到堆栈中,所以esp中的参数会被偏移,就像我们设置一个堆栈帧一样:

    kmemset:      
        push    edi             ; proc uses edi, so save it.
    
        mov     ecx, [esp + 16] ; size_t num
        mov     al, [esp + 12]  ; int value 
        mov     edi, [esp + 8]  ; void * ptr
        rep     stosb 
    
        mov     eax, [esp + 8]  ; return pointer
        pop     edi             ; restore edi
        ret                     ; let caller adjust stack
    

    使用stosw 会有点不同。

    SomeProc:
        push    ebp
        mov     ebp, esp
        push    edi
    
        ; params are at:
         ;~ ebp + 8
         ;~ ebp + 12
         ;~ ebp + 16
         etc...
        ; ...
        ; ...
        ; ...
    
        pop     edi
        ; the following 2 lines
        ; can be replaced with
        ; leave
        mov     esp, ebp
        pop     ebp
        ret
    

    【讨论】:

    • 您好,非常感谢。实际上,我的代码中有两个主要错误,ret 地址缺少 4 个字节的偏移量,以及 esp 寄存器的重置。并感谢功能模板,让事情变得清晰。 (也感谢 gnome 的第一个提示,以及 nrz 的编辑)
    • 可能也想做一个 CLD,以防你突然从 [di] 倒退!
    猜你喜欢
    • 2017-01-13
    • 2014-02-22
    • 1970-01-01
    • 1970-01-01
    • 2011-02-18
    • 2017-01-11
    • 1970-01-01
    • 2015-05-04
    • 2020-12-04
    相关资源
    最近更新 更多