2016-04-26 10 views
2

Ich versuche, x86-Assembler zu lernen, und ich möchte eine NASM Funktion in C aufrufen. Wenn ich mein Programm laufen bekomme ich diesen Fehler:Aufruf der NASM-Funktion in C

Segmentation fault (Core dumped)

Ich habe versucht, Dutzende von Variationen meiner einfachen Testfunktion, aber es stoppt Position jedes Mal an der gleichen.

Hier sind meine asm und c Dateien:

div.asm:

global _test 

_test: 
    push ebp 
    mov  ebp, esp 
    push ebx 
    mov  eax, [ebp+8] 
    mov  ebx, [ebp+12] 
    div  ebx 
    pop  ebp 
    ret 

main.c:

#include <stdio.h> 

extern unsigned int test (unsigned int, unsigned int); 

int main(void) 
{ 
    printf("%d\n", div(85,5)); 
    return 0; 
} 

ich kompilieren & Link, um die Dateien mit:

nasm -f elf -o div.o div.asm 
gcc -m32 -c -o main.o main.c 
gcc -m32 -o run div.o main.o 

Ich verwende eine 64 Bit Linux in einer Virtual Machine.

Was ist mein Fehler hier, und wie kann ich es beheben?

+2

Versuchte Debuggen? – arrowd

+4

Verwenden Sie einen Debugger, um herauszufinden, welche Fehler es gibt. Siehe [der FAQ-Bereich des x86-Tag-Wikis] (http://stackoverflow.com/tags/x86/info), du hast ein paar von ihnen: nicht übereinstimmendes Push/Pop und ein "div" -Problem. –

+1

Oh guter Punkt, yeah, Linux nicht Namen mit einem führenden '_'. Die "Test" -Funktion, die Sie aufrufen, ist nicht einmal die '_test'-Funktion, die Sie zusammengefügt haben! Da es verlinkt, muss das Symbol in einer Bibliothek existieren, denke ich? Wieder Debugger FTW. Kompiliere mit '-g'. Wie 'gcc -m32 -Wall -Wextra -Og -g main.c div.o -o run' –

Antwort

3

Sie vergessen ebx Pop (oder zumindest den Stapel, um zu machen):

push ebp 
mov  ebp, esp 
push ebx   ; you push it here 
mov  eax, [ebp+8] 
mov  ebx, [ebp+12] 
xor  edx,edx  ; ..and you must zero edx 
div  ebx 
pop  ebx   ; forgot to pop it here 
pop  ebp 
ret 
+0

Dies ist nicht das einzige Problem. Die Division macht eine vorzeichenlose Division von EDX: EAX dividiert durch EBX, aber _EDX_ wird nicht auf Null gesetzt. Dies kann zu einem falschen Ergebnis oder einem Teilungsfehler führen, da der Quotient möglicherweise nicht in 32 Bits darstellbar ist. –

+2

Sie müssen das 'ebx' des Aufrufers wiederherstellen! Besser wäre es, ein Register mit erhaltenem Anruf an erster Stelle zu verwenden (z. B. "ecx" verwenden). Noch besser, 'div [ebp + 12]'. –

+0

Wie auch immer, aber wenn er den Stack nicht aufräumt, dann wird "pop ebp" die falsche Base poinetr knacken und der 'ret' springt zu irgendwoher, daher der seg Fehler. –

2

Es ist unklar, ob Sie jemals Ihr Problem gelöst werden. Zusätzlich zu den anderen Problemen müssten Sie Ihren Funktionsanruf in Ihrem main.c Anruf dem Anruf in div.asm machen. Wenn Sie beispielsweise eine Assembly-Funktion _test erstellt haben, müssen Sie sie als extern deklarieren und die Funktion tatsächlich in main verwenden. zB:

#include <stdio.h> 

extern unsigned int _test (unsigned int, unsigned int); 

int main(void) 
{ 
    printf("%d\n", _test (85,5)); /* you are calling div here, not _test */ 
    return 0; 
} 

(Ihr Funktionsname ist nicht der Name für die Assembly Objektdatei div.o - und wie in den Kommentaren darauf hingewiesen, div ist eine Division ohne Vorzeichen erklärte in stdlib.h zusammen mit ldiv und lldiv)

Ihre Deklaration global in Ihrer Assembly-Funktionsdatei muss mit dem Namen übereinstimmen, den Sie in main deklariert haben. z.B .:

global _test 

_test: 
    push ebp 
    mov  ebp, esp 
    mov  eax, [ebp+8] 
    xor  edx, edx 
    div  dword [ebp+12] 
    mov  esp, ebp 
    pop  ebp 
    ret 
Jetzt

, können Sie kompilieren, linken und Ihre Testdatei ausführen:

$ nasm -f elf -o div.o div.asm 
$ gcc -m32 -c -o main.o main.c 
$ gcc -m32 -o run div.o main.o 
$./run 
17 

oder für die Erstellung/link einfach wie folgt:

$ nasm -f elf -o div.o div.asm 
$ gcc -m32 -o run main.c div.o