Umwandlung von float zu ascii-code



  • Hallo!

    Bin neu in der Assembler-Programmierung und ich muss eine 32bit-Gleitkommazahl (float) in ASCII-Format umwandeln!

    Als Vorlage soll die Umwandlung von Int zu ASCII dienen, mit folgendem Code:

    void RNOInteger::toASCII_asm(char str[])
    {
    __asm__ __volatile__( //volatile: Wert der Variable kann immer modifiziert werden
    "XOR %%ebx, %%ebx\n\t" //set string offset to zero
    "loop:\n\t"
    "XOR %%edx, %%edx\n\t" //set edx register to zero
    "MOV $0xa, %%ecx\n\t" //copy radix(=10) to ecx register
    "IDIV %%ecx\n\t" //divide value in eax by the radix in ecx
    "ADD $0x30, %%edx\n\t" //convert remainder to ASCII
    "MOV %%dl, (%%esi,%%ebx,1)\n\t" //save result in string
    "INC %%ebx\n\t" //increment string length
    "CMP $0x0, %%eax\n\t" //break if register eax is empty
    "JNE loop\n\t" //start again
    "MOVB $0x0, (%%esi,%%ebx,1)\n\t" //add string termination
    "XOR %%ecx, %%ecx\n\t" //set reverse index to zero
    "reverse_loop:\n\t"
    "DEC %%ebx\n\t" //decrement string index
    "MOVB (%%esi,%%ebx,1), %%al\n\t" //reverse byte order
    "MOVB (%%esi,%%ecx,1), %%ah\n\t"
    "MOVB %%ah,(%%esi,%%ebx,1)\n\t"
    "MOVB %%al, (%%esi,%%ecx,1)\n\t"
    "INC %%ecx\n\t"
    "CMP %%ecx, %%ebx\n\t"
    "JG reverse_loop\n\t" //if not finished, loop again
    : // no output variables
    : "a" (value), "S" (str)
    : "ebx", "ecx", "edx" // clobber registers
    );
    }

    Kann mir jemand diesen Code genauer erklären??
    und hat jemand eine Idee, wie das Coding für den float ausschauen könnte??
    Bin für jeden Tipp dankbar!!

    lg Stefan



  • Deine Assembler Funktion macht im Prinzip das, was die C-Funktion macht:

    void toASCII_c(char str[])
    {
        int local_value = value;
        int rest = 0;
        unsigned int n = 0u;
        unsigned int i = 0u;
        unsigned int j = 0u;
        char tmp = 0;
    
        do
        {
            rest = (local_value % 10);
            str[n] = (0x30 + rest);
            local_value /= 10;
            ++n;
        }
        while (0 != local_value);
    
        str[n] = 0;
    
        for (i = 0u; i < (n / 2u); ++i)
        {
            j = (n - i - 1u);
            tmp = str[j];
            str[j] = str[i];
            str[i] = tmp;
        }
    }
    

    Ich hoffe, der Code ist selbsterklärend und fehlerfrei 😉 Für negative Zahlen habe ich die C-Funktion nicht getestet, aber Deine Assembler Funktion scheitert bei negativen Zahlen auch.
    Bezüglich der floats oder double oder long doubles habe ich keine Idee. Du musst irgendwie den mathematischen Coprozessor benutzen. Und der unterstützt auch einige Befehle wie FPREM für die Modulo-Berechnung, was Du ja wahrscheinlich gebrauchen kannst... Wenn Du es geschafft hast, könntest Du bitte den Code hier posten? Interessiert mich jetzt auch, wie es gehen könnte. Habe mit dem Coprozessor seit längerem nichts gemacht, wäre schön, noch mal das eine oder andere zu wiederholen...



  • void RNOFloat::toASCII_asm(char str[])
    {
    // add your inline-assembler code of the algorithm here

    //int RNOFloat (float value, char* str)
    //{
    // int len;
    float RNOFloat = value;

    __asm__ __volatile__

    "FINIT\n\t" //;Initialize Co-Processor
    "SUB $0x8, %%esp\n\t" //; Platz für FPU-Zwischenergebnisse
    "FLDZ\n\t" //; ST(0)=0 --> Load Z (Zero) on Stack
    "MOVW $0xa, (%%esp)\n\t" //* Move word 10 nach esp (Basepointer-Register)

    // "FILD word ptr [%%esp]\n\t" //* //; ST(0)=10 ST(1)=0
    "FILD (%%esp)\n\t" //Push source %%esp on stack

    "FSTCW (%%esp)\n\t" //Store Control word register
    //"OR 0x0C00, word ptr [esp]\n\t" //

    "ORW $0x180, (%%esp)\n\t" //* //; Truncating Mode (abschneiden) word(W) von Basepointer esp
    "FLDCW (%%esp)\n\t" //*Load Control Word register from source (=%%esp)

    "MOV str, %%edi\n\t" //* //; Offset für alle stosb-Operationen
    //mov al, byte ptr [value+7]
    "MOVB (RNOFloat+0x7),%%al\n\t" //* //; oberstes Byte (Move Byte von Byte 7 value ins Register %%al)
    "OR %%al, %%al\n\t" //*
    "JNS S1\n\t" //; Jump No Sign (positiv: nichts machen)
    "MOV '-',%%al \n\t" //* //;
    "STOSB\n\t" //; Store Byte (Negativ-Vorzeichen nach value)

    "S1:\n\t" //; Vorkommazahl nach [esp]
    //"FLD qword ptr [value]\n\t" //; ST(0)=d ST(1)=10 ST(2)=0
    "FLD (RNOFloat)\n\t" //push source (=value) on stack
    "FABS\n\t" //; positiv STO = |STO|
    "FLD %%ST\n\t" //; ST(0)=d ST(1)=d ST(2)=10 ST(3)=0 //push src on stack
    "FRNDINT\n\t" //; ST(0)=int(d) ST(1)=d ST(2)=10 ST(3)=0 //runde STO
    "FLD %%ST\n\t" //; ST(0)=int(d) ST(1)=int(d) ST(2)=d ST(3)=10 ST(4)=0 //Push st on stack
    // "FISTP qword ptr (esp)\n\t" //; ST(0)=int(d) ST(1)=d ST(2)=10 ST(3)=0
    "FIST (%%esp)\n\t" //; Store STO
    //"FSUBP ST(1), ST\n\t" //; ST(0)=d-int(d) ST(1)=10 ST(2)=0
    "FSUB %%ST,%%ST(1)\n\t" //FSUBP dest [,ST0] dest -= ST0
    //xchg ebp, [esp+4]
    "XCHG (%%esp,4),%%ebp\n\t" //* //; ebp:esi = Vorkommazahl, altes ebp sichern
    //mov esi, [esp+0] 0?????????????????????
    "MOV (%%esp),%%esi\n\t" //*
    "MOV $0xa, %%ebx\n\t" //* //; Divisor
    "XOR %%ecx, %%ecx\n\t" //* //; Push-Zähler

    "L1:\n\t" // MOD 10 auf den Stack
    "XOR %%edx, %%edx\n\t" //*
    "MOV %%ebp, %%eax\n\t" //*
    "DIV %%ebx\n\t" //*
    "MOV %%eax, %%ebp\n\t" //*
    "MOV %%esi, %%eax\n\t" //*
    "DIV %%ebx\n\t"
    "MOV %%eax, %%esi\n\t" //*
    "PUSH %%dx\n\t" //* // PUSH to Stack
    "INC %%cl\n\t" //*
    "OR %%esi, %%esi\n\t" //*
    "JNE L1\n\t" //Jump not equal
    "OR %%ebp, %%ebp\n\t" //*
    "JNE L1\n\t"

    "L2:\n\t" //Stack nach dez
    "POP %%ax\n\t" //* //POP from Stack
    "OR 0x30,%%al\n\t" //* //; ASCII
    "STOSB\n\t"
    "loop L2\n\t"
    //mov ebp, [esp+4]
    "MOV (%%esp,0x4),%%ebp\n\t" //* //; altes ebp zurück

    // "FCOMI st(0), st(2)\n\t" //; Nachkommazahl = 0 ?
    "FCOMI %%ST(2),%%ST(0)\n\t" // Floating Point Compare, move result to EFLAGS
    "JZ S2\n\t" //; ja: Ausstieg
    "MOV '.',%%al \n\t" //* //; Dezimalpunkt nach dez
    "STOSB\n\t"
    "MOV $0x136,%%ecx\n\t" //* //; Maximale Anzahl an Nachkommastellen

    "L3:\n\t" // Nachkommazahl nach dez
    "FMUL %%ST(1), %%ST\n\t" //; Eine Dezimalzahl in den Vorkommabereich holen
    //"FIST word ptr [esp]\n\t" //; Vorkommazahl zwischenspeicherm
    "FIST (%%esp)\n\t"
    //"FISUB word ptr [esp]\n\t" //; Vorkommazahl abschneiden
    "FISUB (%%esp)\n\t"
    "MOVB (%%esp),%%al\n\t" //*
    "OR 0x30,%%al\n\t" //* //; Integer -> ASCII
    "STOSB\n\t"
    // "FCOMI %%ST(2),%%ST\n\t"
    "FCOMI %%ST(2), %%ST(0)\n\t" //; noch was übrig?
    "JZ L3\n\t" //; nein: Ausstieg
    "loop L3\n\t"
    //"MOV $0xa, %%ecx\n\t"

    "S2: fninit\n\t" //; FPU aufgeräumt zurückgeben
    "ADD $0x8,%%esp\n\t" //* //; FPU-Platz wieder freigeben
    "MOVB $0,(%%edi)\n\t" //; ASCIIZ-Abschlussnull

    "MOV str, %%eax\n\t" //*
    "SUB %%eax, %%edi\n\t" //*
    // "MOVL %%edi,(len)"

    : // no output variables
    : "a" (value), "S" (str)
    : "ebx", "ecx", "edx"

    );

    }

    funktioniert super! 👍
    nur bekomme ich jeweils 2 errors:
    undefined reference to RNOFloat
    und undefined reference to str (sind parameter aus der Headerdatei)
    ??????????



  • Na ja, funktioniert super. Bekomme auch ähnliche Fehlermeldung(en):

    C:\DOKUME1\abcw\LOKALE1\Temp/ccPRaRa7.s: Assembler messages:
    C:\DOKUME1\abcw\LOKALE1\Temp/ccPRaRa7.s:80: Warning: scale factor of 4 without an index register
    C:\DOKUME1\abcw\LOKALE1\Temp/ccPRaRa7.s:103: Warning: scale factor of 4 without an index register
    mingw32-gcc main.o -o main.exe -Wall -Wextra -pedantic
    main.o:main.c: (.text+0x79): undefined reference to str' main.o:main.c: (.text+0x7e): undefined reference toRNOFloat'
    main.o:main.c: (.text+0x8e): undefined reference to RNOFloat' main.o:main.c: (.text+0x104): undefined reference tostr'
    collect2: ld returned 1 exit status
    make: *** [all] Error 1

    Irgendwas ist komlett falsch... Trotzdem, danke.


Log in to reply