需要有两点注意:
- .type在windows的mingw上无法识别。
- windows下编译会找不到my_strcpy的定义(undefined reference),通过看mingw的代码发现,它会在汇编函数前加一个下划线,所以在我们的汇编代码中加上下划线即可。
维基百科中关于cdecl的阐述,中文版有一条:编译后的函数名前缀以一个下划线字符,但英文版中没有这一条。
且加上下划线后在windows下mingw虽然不再报错,但在linux下gcc又会报undefined reference。
具体原因尚不明确。
32位
.text.globl my_strcpy
.type my_strcpy, @function #.type伪指令在windows下编译会无法失败,可以去掉my_strcpy:movl 8(%esp), %edx #sourcemovl 4(%esp), %eax #destpushl %ebp #保存旧栈底movl %esp, %ebp #保存栈顶,结束时恢复movb (%edx), %cl #从source取一个字节,放到cltest %cl, %cl #判断cl是否为0je return #为0就returnbody:movb %cl, (%eax) #把从source取的一个字节放到destmovb 1(%edx), %cl #取source的下一个字节inc %eax #递增dest索引inc %edx #递增source索引test %cl, %cl #判断取的字节是否为0jne body #不为0就继续循环return:movl $0, (%eax) #给dest的字符串结尾加上'\0'movl %ebp, %esp #恢复栈顶popl %ebp #恢复栈底ret #返回
64位
.text.globl my_strcpy
.type my_strcpy, @function_my_strcpy:pushq %rbpmovq %rsp, %rbpmovq %rdi, %rdx #destmovq %rsi, %rax #srcmovb (%rax), %cltest %cl, %clje return
body:movb %cl, (%rdx)movb 1(%rax), %clinc %raxinc %rdxtest %cl, %cljne bodyreturn:movq $0, (%rdx)movq %rbp, %rsppopq %rbpret
使用
main.c:
#include <stdio.h>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