需要有两点注意:
维基百科中关于cdecl的阐述,中文版有一条:编译后的函数名前缀以一个下划线字符,但英文版中没有这一条。
且加上下划线后在windows下mingw虽然不再报错,但在linux下gcc又会报undefined reference。
具体原因尚不明确。
.text
.globl my_strcpy
.type my_strcpy, @function #.type伪指令在windows下编译会无法失败,可以去掉
my_strcpy:
movl 8(%esp), %edx #source
movl 4(%esp), %eax #dest
pushl %ebp #保存旧栈底
movl %esp, %ebp #保存栈顶,结束时恢复
movb (%edx), %cl #从source取一个字节,放到cl
test %cl, %cl #判断cl是否为0
je return #为0就return
body:
movb %cl, (%eax) #把从source取的一个字节放到dest
movb 1(%edx), %cl #取source的下一个字节
inc %eax #递增dest索引
inc %edx #递增source索引
test %cl, %cl #判断取的字节是否为0
jne body #不为0就继续循环
return:
movl $0, (%eax) #给dest的字符串结尾加上'\0'
movl %ebp, %esp #恢复栈顶
popl %ebp #恢复栈底
ret #返回
.text
.globl my_strcpy
.type my_strcpy, @function
_my_strcpy:
pushq %rbp
movq %rsp, %rbp
movq %rdi, %rdx #dest
movq %rsi, %rax #src
movb (%rax), %cl
test %cl, %cl
je return
body:
movb %cl, (%rdx)
movb 1(%rax), %cl
inc %rax
inc %rdx
test %cl, %cl
jne body
return:
movq $0, (%rdx)
movq %rbp, %rsp
popq %rbp
ret
main.c:
#include
extern void my_strcpy(char*, const char*);
int main(void)
{
char str_1[1024];
char str_2[]="hello world";
my_strcpy(str_1, str_2);
puts(str_1);
}
假设my_strcpy
定义在my_strcpy.s
汇编代码文件中。
对于32位,编译:gcc main.c my_strcpy.s -o main -m32
,64位不带-m32
就行了。
链接器可能会报可执行堆栈的警告:
/usr/bin/ld: warning: /tmp/ccJvbhJo.o: missing .note.GNU-stack section implies executable stack
/usr/bin/ld: NOTE: This behaviour is deprecated and will be removed in a future version of the linker
可以加上-z noexecstack
,或者在汇编代码里面加上这一行:
.section .note.GNU-stack,"",@progbits