Я пробовал вызывать ASM из C и наоборот. По крайней мере, на данный момент это работало идеально, но у меня есть вопросы. Вот мой код:
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)
Должен ли я написать это информирование op. если функция объявлена в файле 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, но как насчет других?)
Спасибо за все ваши ответы.