我尝试过从C调用ASM,反之亦然。至少现在它完美无缺,但我有疑问。这是我的代码:
接下来是test.S
.text
.global _start
.global _main
.type _main, @function
.global writeMe
.type writeMe, @function
_start:
#; Write hello world for 5 times.
#; Jump exit and call C function after that.
#; C function calls writeMe assembly function
#; Exit with syscall
xorl %ecx, %ecx #; ecx = 0
call _get_eip #; get eip without labels. Just for research.
pushl %eax #; push to stack
incl %ecx #; ++ecx
pushl %ecx #; push to stack
movl $len,%edx #; tell length of string
movl $msg,%ecx #; tell string position
movl $1,%ebx #; fd = stdout
movl $4,%eax #; syscall = write
int $0x80 #; perform call
popl %ecx #; pop counter
movl %ecx, %eax #; eax = ecx
cmpl $0x5, %eax #; compare 0x5 and eax
je _exit #; eax == 0x5, jump exit
_jmp:
popl %eax #; pop instruction pointer
jmpl %eax #; jmp
_exit:
call _main #; call C function
movl $0,%ebx #; EXIT_SUCCESS
movl $1,%eax #; syscall = exit
int $0x80 #; perform call
ret
_get_eip: #; function for getting eip
popl %eax #; pop eip
pushl %eax #; push again to return
ret #; return location
writeMe: #; function for writing, called from C
popl (__eip) #; pop return location
popl %ecx #; pop first argument, msg
popl %edx #; pop second argument, len
movl $1, %ebx #; fd = stdout
movl $4, %eax #; syscall = write
int $0x80 #; perform call
pushl (__eip) #; push return location
ret #; return location
writeMe2: #; function for writing, called from C
popl %ecx #; pop return location
popl %ecx #; pop first argument, msg
popl %edx #; pop second argument, len
movl $1, %ebx #; fd = stdout
movl $4, %eax #; syscall = write
int $0x80 #; perform call
subl $0x0C, %esp #; restore stack
ret
.data
__eip: .long
msg:
.ascii "Hello, world!\n\0"
len = . - msg
main.C紧随其后:
extern void writeMe(const char *msg, int len);
int _strlen(const char *msg) {
int _len = 0;
while (*msg++ != 0x0)
_len++;
return _len;
}
void _main() {
const char * szmsg = "Hello, world!\n";
writeMe(szmsg, _strlen(szmsg));
}
我的输出就像我预期的那样。
你好,世界!
你好,世界!
你好,世界!
你好,世界!
你好,世界!
你好,世界!
我的问题随之而来:
1)
.type writeMe, @function
这段代码是什么意思? “GCC”的信息?它有什么作用?我必须这样做吗?
2)
我是否必须写这个通知操作。如果函数在C文件中声明?
.type _main, @function
_main在C文件中声明,我必须写吗?
第3)
popl (__eip) #; pop return location
popl %ecx #; pop first argument, msg
popl %edx #; pop second argument, len
........
pushl (__eip) #; push return location
我在writeMe中使用过这段代码,安全吗?换句话说,我可以弹出参数,还是GCC会自动弹出它?
popl %ecx #; pop return location
popl %ecx #; pop first argument, msg
popl %edx #; pop second argument, len
....
subl $0x0C, %esp #; restore stack
我在第二个函数中使用了这段代码。我问你,哪一个是安全和正确的?
4) 从C调用汇编函数后,是否需要恢复寄存器? (我听说我必须恢复EDI,但其他人呢?)
感谢您的所有回复。
答案 0 :(得分:3)
1)设置要运行的符号类型。除特殊情况外,不需要它,例如共享库。
2)不,编译器已经为C中定义的函数完成了。
3)这两个都是错的。您应该访问相对于esp
的参数,或者在设置标准堆栈帧后,相对于ebp
。
4)您应阅读相应的ABI文档,以获取有关调用约定的信息。通常,您可以使用eax
,ecx
和edx
,其余部分必须保留。