2009-10-11 14 views
6

Trabajaré en un gran proyecto de ensamblaje pero ahora estoy empezando a aprender este nuevo idioma. Estoy tratando de hacer algunos ejemplos simples como los que puede encontrar para C++ en la escuela secundaria (sumar dos números, es un número primo, etc.).Función de llamada C desde ensamblador: la aplicación se congela en "call printf" y no tengo idea de por qué

Ahora tengo que mostrar todos los números primos hasta n. El problema es que la aplicación se congela en "call printf" y no tengo idea de por qué.

¿Me pueden ayudar con esto?

.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 

Respuesta

4

Es probablemente debido a que sus registros están en mal estado después de la llamada printf, es necesario guardar los registros que tienden a usar después de printf y luego restaurarlos después de la llamada.

Esto es algo que debe hacer siempre cuando hace syscall u otras llamadas que podrían alterar sus registros.

También debe fijarse en gdb (depurador GNU) parece que se está codificando GAS así que si usted está en un sistema de prueba GNU/Linux:

gdb youprogram 

y luego ejecutarlo para ver donde falla.

1

Tenga en cuenta también que en C/C++ necesita extraer los registros usted mismo (en la conversión de llamada Pascal, el procedimiento emite un "ret 8", por ejemplo).

2

Otro problema es que no se limpia correctamente la pila después de la llamada a printf. Necesita agregar 8 a ESP porque ha pulsado ECX (4 bytes) y una dirección (4 bytes en el modo de 32 bits).

Además, tenga en cuenta que, al menos en Windows (utilizando MinGW), printf pisa fuerte en EAX (valor de retorno), ECX y EDX, y modifica EFLAGS. Al igual que todas las funciones C estándar, que he usado hasta ahora, para el caso.

Cuestiones relacionadas