2016-05-08 12 views
0

Ich versuche, meinen ANSI C-Code mit ASM (TASM, um genau zu sein) Modul zu kombinieren.
Ich entschied mich, die klassische Aufgabe zu wählen - Durchschnitt der Zahlen im Array zu bekommen, und es funktioniert fast, es kompiliert und verbindet erfolgreich, aber am Ende heißt es, dass der Durchschnitt gleich -0 ist (wenn nicht).Durchschnitt der float [] Array (Intel 8086)

Was habe ich falsch gemacht? Hier ist der benötigte Teil meines .c Code:

#include <stdio.h> 
extern float avg(int, float*); 

int main() 
{ 
    int n = 2; 
    float tab[] = {2.0, 3.0}; 
    printf("%.3g\n", avg(n, tab)); 

    return 0; 
} 

Und .asm Verfahren:

avg PROC 
    finit 
    push BP 
    mov BP, SP 

    push bx 
    mov cx, [bp+4]  ; no of elements 
    mov bx, [bp+8]  ; address 

    fldz ; zero 
    jcxz avg_end ; if cx==0, end 

    iter: 
    fadd DWORD PTR [bx] 
    add bx, 4 
    loop iter 

    fidiv DWORD PTR [bp+4] ; sum/n 

    avg_end: 
    pop bx 
    pop BP 
    ret 
avg ENDP 

Mein Programm hat auch eine weitere externe Funktion innerhalb und es funktioniert gut.
Das einzige Problem muss innerhalb avg PROC Code sein. Ich würde deine Ideen schätzen!

+1

Warum 8 zu 'bx' hinzugefügt wird? Sind Sie sicher, dass "float" in Ihrer Umgebung 8 Bytes beträgt? – MikeCAT

+0

Schreiben Sie tatsächlich ein 16-Bit-DOS-Programm? Wenn ja warum? – zwol

+1

Verwenden von Offset 4 zwischen Argumenten in 16-Bit-Umgebung sieht auch seltsam aus. Sind Sie sicher, dass es entlang Ihrer ABI ist? – MikeCAT

Antwort

0

Ich habe es. Es scheint, ich hatte zwei Probleme dort:

  • Vor allem - Adressierung.
    bx Register sollte mit [bp+6] statt [bp+8] gefüllt werden.
    Das ist offensichtlich, weil meine erste Arg ist Ganzzahl, 2B lang, nicht wahr?

  • Zusätzlich, @Sep Roland war richtig mit meiner fidiv Anweisung.
    Mein Wert ist nicht einmal DWORD, es ist nur WORD und es behebt alle meine Probleme.

Es funktioniert jetzt, vielen Dank für Ihre Zeit.
Ich konnte meine Frage nicht löschen, also poste ich meine Antwort, vielleicht wird es eines Tages nützlich sein.

3

Im Real-Adress-Modus ist ein Zeiger nicht nur ein Offset. So holen das zweite Argument float * müssten Sie:

lds bx, [bp+8]  ;full pointer 

Vielleicht möchten Sie push ds/pop ds.

Ist das 1. Argument sogar ein Doppelwort? Sie könnten versuchen:

fidiv WORD PTR [bp+4] ; sum/n 
1

Warum knallen Sie nie etwas aus dem FP-Stapel?

Sie fehlen mindestens eine endgültige fstp DWORD PTR [bp] vor der Rückkehr. Je nachdem, wo Ihr ABI den Rückgabewert haben möchte.

Derzeit drängen Sie auf den FP-Stack, berechnen den Durchschnitt, und das war's. Sie haben ein Register durchgesickert und haben sich nie das Ergebnis angesehen.

+0

Soweit ich weiß, sollte das Ergebnis, wenn ich den Gleitkommawert zurückgebe, oben auf dem FPU-Stapel "st (0)" platziert werden. Ist es nicht so? – 5208760

+1

Hängt von der ABI ab, die der Compiler gewählt hat. 'Hardfp' vs.' Softfp'. Das letztere übergibt Parameter und Rückgabewerte auf dem regulären Stapel/Register, der erste schiebt und erwartet alle FP-Parameter und gibt den Wert auf dem FP-Stapel zurück. Nur im 'cdecl'-ABI wird' st (0) 'verwendet, um zurückzukehren. – Ext3h