Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Call C function from Assembly -- the application freezes at "call printf" and I have no idea why

I will be working on a big Assembly project but am now just starting to learn this new language. I am trying to make some simple examples like you might find for c++ in highschool (sum two numbers, is a number prime, etc).

Now I've got to display all prime numbers up to n. The problem is that the application freezes at "call printf" and I have no idea why.

Can you help me with this?

.section    .data
prime_number_str:
.asciz  "%d "

.section    .text

.global     _start
_start:
pushl   $20
call .first_prime_numbers
addl $4, %esp
pushl $0
call exit


.first_prime_numbers:       #argument first n numbers
movl 4(%esp), %ecx  #get the first argument
do_test:
pushl %ecx      #push function arguments
call .prime 
addl $4, %esp       #restore the stack

#if not prime jump to the next number   
cmpl $0, %eax
je no_not_prime

#print the number
pushl %eax          #save eax
pushl %ecx          #first argument
pushl $prime_number_str     #text to print
call printf
addl $4, %esp
popl %eax           #restore eax

no_not_prime:
loop do_test
ret


.prime:             #argument: number to check
movl 4(%esp), %eax  #get the first argument

#divide the argument by 2   
xorl %edx, %edx             
movl $2, %ecx           
pushl %eax      #save the value of eax
divl %ecx       
movl %eax, %ecx     #init the counter register
popl %eax       #restore the value of eax

movl $1, %ebx       #assume the argument is prime
test_prime:
# if ecx == 1 then return exit the function
cmpl $1, %ecx       
jle return_value

pushl %eax      #save the old value of eax  

#divide the value by the value of counter   
xorl %edx, %edx     
divl %ecx       

#if the reminder is 0 then the number is not prime
cmpl $0, %edx   
popl %eax       #restore the value of eax   
je not_prime


subl $1, %ecx       #decrease counter
jmp test_prime      #try next division

not_prime:
movl $0, %ebx
return_value:
movl %ebx, %eax
ret 
like image 986
DavidH Avatar asked Oct 11 '09 14:10

DavidH


3 Answers

It is probably because your registers are all messed up after called printf, you need to save the registers that you tend to use after printf and then restore them after the call.

This is something you should do Always when you do syscall or other calls that might tampere with your registers.

Also you should look into gdb ( gnu debugger ) looks like you are coding GAS so if you are on a gnu / linux system try:

gdb youprogram

and then run it to see where it fails.

like image 122
Filip Ekberg Avatar answered Nov 18 '22 06:11

Filip Ekberg


One other issue is that you're not properly cleaning up the stack after the call to printf. You need to add 8 to ESP because you pushed ECX (4-bytes) and an address (4-bytes in 32-bit mode).

Also, note that, at least on Windows (using MinGW), printf stomps on EAX (return value), ECX, and EDX, and modifies EFLAGS. As do all of the standard C functions, that I've used thus far, for that matter.

like image 23
Jordan Pickwell Avatar answered Nov 18 '22 06:11

Jordan Pickwell


Please also note, that in C/C++ you need to pop out the registers yourself (in Pascal calling convertion, the procedure issues a "ret 8" for example).

like image 23
elcuco Avatar answered Nov 18 '22 07:11

elcuco