Reputation: 41
I've tried some calling ASM from C and vice versa. It worked perfect at least for now but I have questions. Here is my code:
test.S followed:
.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 followed:
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));
}
My output is like what I expected.
Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!
My questions followed:
1)
.type writeMe, @function
What does this code mean? Information for "GCC" ? What does it do? Do I have to do that?
2)
Do I have to write this informing op. if function declared in C file?
.type _main, @function
_main is declared in C file, do I have to write ?
3)
popl (__eip) #; pop return location
popl %ecx #; pop first argument, msg
popl %edx #; pop second argument, len
........
pushl (__eip) #; push return location
I've used this code in writeMe, is it safe? In other words, can I pop arguments, or will GCC pop it automatically?
popl %ecx #; pop return location
popl %ecx #; pop first argument, msg
popl %edx #; pop second argument, len
....
subl $0x0C, %esp #; restore stack
I've used this code in second function. I am asking you, which one is safe and correct?
4) Do I need to restore registers after calling assembly function from C ? (I heard I have to restore EDI but what about others?)
Thanks for all your replies.
Upvotes: 0
Views: 1169
Reputation: 58762
1) Sets the type of the symbol to function. It's not needed, except in special cases, for example shared libraries.
2) No, that has been done by the compiler for the functions defined in C.
3) Both of those are wrong. You should access arguments relative to esp
or, after setting up a standard stack frame, relative to ebp
.
4) You should read the appropriate ABI documentation for information about the calling convention. Typically, you can use eax
, ecx
and edx
the rest must be preserved.
Upvotes: 3