我正在尝试在程序集 x86 中实现 memset。都有一个按字节和按字的副本,所以我会得到两个函数:kmemset
和 kmemsetw
,我以这种方式公开给我的 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
最佳答案
你在你的程序中没有使用 ebx
,为什么要保存它?它不需要保存。 ecx
是一个 volatile 寄存器,你不需要保存它。
正如提到的 gnometorule,您的 proc 中的参数已关闭。
另一个大问题是你没有在最后恢复堆栈指针。当然你 pop ebp
,但是你在哪里 mov esp, ebp
???您在开始时使用 mov ebp, esp
,但永远不要反转它。
如果您查看 memset
,它会返回传递给 proc 的指针。所以,这是错误的:mov eax, edi
应该是: mov eax, [ebp + 8]
。 rep stos?
增加 edi
中的指针,因此如果您返回 edi
,则返回的指针是错误的。
但是为什么还要为这个小小的 proc 设置一个堆栈框架呢?只需使用 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
关于assembly - 在程序集 x86 中实现 memset,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/20331000/