2009-12-22 3 views
0

Je suis nouveau dans le langage d'assemblage et je dois implémenter une fonction, dans mon cas sin (x), qui pourrait être appelée à partir d'un fichier source C. Je dois faire 2 fichiers séparés: * .c et * .s Lors de la compilation par gcc sur ubuntu tout bon, mais quand le programme exécute me donne l'erreur « Segmentation fault » ...Erreur de segmentation lors de l'exécution du programme compilé à partir de l'assemblage x86?

Pour compiler I Type:

gcc -c -o sinc.o sinx.c -g3 
gcc -c -o sins.o sinx.s -g3 
gcc -o sinx sinc.o sins.o -g3 

Quand je commence le programme:

./sinx 

Il imprime:

.......insert x: 

je mets x et puis:

segmentation fault 

et arrête. Voici les deux fichiers:

/*-----------------------------------Sin[x]----------------------------------------*/ 

extern float Sin(float x);        //extern assembly function 

#include <stdio.h>            //necessary libraries 

int main()               // main function 
{ 
    float x;          //allocate variable 'x' as a float 
    float sine;        //allocate variable 'sine' as a float 

    printf("Calculate Sin[x], with 'x' in radians\n");  //purpose of the program 

    printf("Insert 'x': ");           //user prompt 
    scanf("%f",&x);            //get input value 

    sine=Sin(x);             //calculate sin(x) 

    printf("Sin[%f]=%f\n",x,sine);          //print sin(x) 

    return 0;              //successful exit 
} 
/*----------------------------------------------------------------------------------*/ 

et

#---------------------------Sin[x]-----------------------------# 
.data 
.text 
.globl Sin    #global function visible by main function 

#function sumplus 
sumplus: 
    pushl %ebp 
    movl %esp,%ebp 
    fld1            #load 1 in ST(0) 
    movl 12(%ebp),%ecx          #ecx=i 
power: 
    fmul %st(0),%st(1)     #ST(0)=ST(0)*ST(1),ST(1)=x 
    loop power        #at the end ST(0)=x^i 
    movl 12(%ebp),%ecx          #ecx=i 
    xorl %edx,%edx       #reset edx used in mul 
    movl $1,%eax         #set accumulator 
factorial: 
    mul %ecx           #eax=eax*ecx 
    loop factorial        #at the end eax=i! 
    pushl %eax 
    fild -4(%ebp)      #ST(0)=i!,ST(1)=x^i,ST(2)=x 
    popl %eax 
    fdiv %st(1),%st(0)     #ST(1)=ST(1)/ST(0)=(x^i)/i! 
    fld 8(%ebp)      #load partial result in ST(0) 
    fadd %st(0),%st(2)    #ST(0)=updated partial result 
    fstp 8(%ebp)    #store partial result into the stack 
    fcomip %st(0),%st(0)          #pop i! 
    fcomip %st(0),%st(0)       #pop x^i/i!,ST(0)=x 
    leave 
    ret 

#function summinus 
summinus: 
    pushl %ebp 
    movl %esp,%ebp 
    fld1            #load 1 in ST(0) 
    movl 12(%ebp),%ecx          #ecx=i 
power2: 
    fmul %st(0),%st(1)     #ST(0)=ST(0)*ST(1),ST(1)=x 
    loop power2        #at the end ST(0)=x^i 
    movl 12(%ebp),%ecx          #ecx=i 
    xorl %edx,%edx       #reset edx used in mul 
    movl $1,%eax         #set accumulator 
factorial2: 
    mul %ecx           #eax=eax*ecx 
    loop factorial2        #at the end eax=i! 
    pushl %eax 
    fild -4(%ebp)      #ST(0)=i!,ST(1)=x^i,ST(2)=x 
    popl %eax 
    fdiv %st(1),%st(0)     #ST(1)=ST(1)/ST(0)=(x^i)/i! 
    fld 8(%ebp)      #load partial result in ST(0) 
    fsub %st(0),%st(2)    #ST(0)=updated partial result 
    fstp 8(%ebp)    #store partial result into the stack 
    fcomip %st(0),%st(0)          #pop i! 
    fcomip %st(0),%st(0)       #pop x^i/i!,ST(0)=x 
    leave 
    ret 

#function develop 
develop: 
    pushl %ebp 
    movl %esp,%ebp 
    sub $8,%esp    #allocate room for local variables 
    movl $9,-4(%ebp)  #store development-order,only odd values 
    fldz           #load 0.0 in ST(0) 
    fstp -8(%ebp)   #store ST(0) and pop to collect results 
Cycle: 
    movl -4(%ebp),%eax     #eax=i,development-order 
    xorl %edx,%edx      #reset edx because of div 
    sub $1,%eax            #i-1 
    movl $2,%ecx           #divisor 
    div %ecx         #eax=(i-1)/2,edx=0 
    div %ecx   #eax=((i-1)/2)/2,remainder edx=0 or edx!=0 
    movl %edx,%ecx         #ecx=remainder 
    jecxz Sumplus         #n even,(-1)^n=+1 
Summinus: 
    call summinus         #n odd,(-1)^n=-1 
    jmp Restore      #if sum- occured skip sum+ 
Sumplus: 
    call sumplus 
Restore: 
    movl -4(%ebp),%ecx       #restore counter 
    sub $2,-4(%ebp)         #update order 
    loop Cycle          #decrement ecx 
    fcomip %st(0),%st(0)          #pop x 
    fld -8(%ebp)      #load final result in ST(0) 
    leave 
    ret 

#function sin 
Sin: 
    pushl %ebp 
    movl %esp,%ebp 
    fld 8(%ebp)     #push onto the stack 'x' value 
    fldpi       #load pi into ST(0),x in ST(1) 
ControlPi: 
    fcomi %st(1)        #compare pi and x 
    jae LoadNPi    #stop ControlPi, x is less than pi 
    fsub %st(1),%st(0)      #store (x-pi) in ST(1) 
    jmp ControlPi       #return to control 
LoadNPi:    
    fimul -1       #(-pi) in ST(0),x in ST(1)     
ControlPi2: 
    fcomi %st(1)        #compare -pi and x 
    jbe PopStack  #stop ControlPi2, x is greater than -pi 
    fadd %st(1),%st(0)      #store (x+pi) in ST(1) 
    jmp ControlPi2       #return to control 
PopStack: 
    fcomip %st,%st(0) #compare -pi to -pi then pop register stack 
    call develop       #call develop function 
    leave            #restore ebp 
    ret              #return 

Alors, où sont les erreurs? Comment puis-je résoudre ce problème? Merci.

Répondre

4

Je suggère de créer une fonction de langage d'assemblage très simple qui ne fait que renvoyer le même argument qu'il est passé. Cela équivaudrait à la fonction C:

float identity(float x) { 
    return x; 
} 

Faire ce travail veillera à ce que vous avez tous la compilation, l'assemblage, la liaison, les conventions d'appel, etc tous mis en place correctement avant de commencer à écrire du code en fait. Une fois que cela fonctionne, écrivez une fonction pour ajouter 1 à l'argument et le renvoyer. Ensuite, commencez à implémenter votre fonction Sin() après vous être entraîné. Ce que vous avez jusqu'ici, c'est beaucoup de code pour quelqu'un de nouveau dans le langage d'assemblage.

+0

J'ai déjà programmé dans cette langue mais ce "projet" est un peu plus difficile que d'autres programmes, comme les factoriels, les sommes partielles, les pouvoirs etc. Je suis nouveau dans le sens où je suis aux premiers pas mais en fait j'ai déjà fait quelques petits pas ... :) – asm

+1

Ok, bien le temps de sortir le débogueur alors! Bonne chance. :) –

+1

@asm: vous avez de bons conseils. Il y a beaucoup de problèmes avec l'asm, vous ne configurez pas le cadre de pile correctement, vous n'initialisez pas les variables locales, vous ne gérez pas correctement la pile FPU. Étudiez d'abord le code généré par le code C. –

1

Généralement, la famille de registres ax (eax incluse) doit conserver la valeur de retour dans l'assemblage. Avez-vous vérifié et confirmé que la valeur est en effet stockée là. Vous pourriez vouloir utiliser un gestionnaire de signal et piéger le SIGSEGV et faire un system(...) décorticage à gdb en utilisant getpid() et attacher au processus et faire une trace de la pile.

En fonction d'exemple utilisé dans le gestionnaire de signal lorsque SIGSEGV est piégé:

 
char buf[150]; 
sprintf(buf, "echo where | gdb -a %d > mydump.data", getpid()); 
system(buf); 

Ensuite, vous pouvez consulter le dossier mydump.data et vérifier où exactement il est seg-formation de failles. Les valeurs par défaut sont le résultat d'une déconnexion d'un pointeur non initialisé ou non mallocidé.

Espérons que cela aide, Cordialement, Tom.

+0

Eh bien, je ne sais pas à propos de SIGSEGV et les autres choses mentionnées. J'ai lu quelque part que pour un float le résultat est retourné dans st (0) de la FPU ... si j'écris factorial = fact (x), fact() doit retourner la valeur de l'entier dans le registre% eax, mais si la valeur est flottante, elle ne peut pas être retournée dans un registre général de 32 bits .... c'est ce que j'ai lu ... – asm

+0

@asm: Voir mon autre réponse ici ... http: // stackoverflow. com/questions/1843747/pourquoi-would-buffer-overruns-cause-segmentation-faults-when-accédant-un-integer/1843939 # 1843939 – t0mm13b

2

Attendez-vous vraiment que quelqu'un débogue cela pour vous?

L'instruction parcourt l'ensemble dans le débogueur, puis pose la question. "Mes valeurs de registres sont a, b, c ..., et j'ai exécuté l'instruction blah". Pourquoi ce piège?En guise de préparation, vous devriez minimalement avoir lu le texte pour l'instruction de piégeage dans la référence du jeu d'instructions d'intel, disponible ici:

http://www.intel.com/products/processor/manuals/

1

Il y a plus d'un bogue dans cette fonction assembleur :)

  1. L'utilisation de gdb indique que la segfault se produit sur l'instruction fimul.
  2. Vous ne pouvez pas utiliser fimul avec un opérande littéral comme ça; l'opérande doit être l'adresse de la valeur de 32 bits que vous voulez multiplier, pas la valeur littérale elle-même.
  3. Pour changer le signe de st0, il est certainement plus facile à utiliser fchs.
  4. Même avec ces changements, votre fonction assembleur ne fonctionne pas (mais au moins, il n'a pas Segfault, et il ne retourne la valeur correcte dans le cas où l'argument est nul!)
+0

Heh, bon appel. Mais ce n'est pas un opérande littéral immédiat, ce serait «$ -1». 'fimul -1' dans la syntaxe AT & T est une charge de l'adresse absolue' -1', d'où le segfault. ('fimul $ -1' serait une erreur d'assemblage.) –

Questions connexes