Partage
  • Partager sur Facebook
  • Partager sur Twitter

assembleur addition float

Sujet résolu
    5 juillet 2021 à 1:01:04

    Bonjour.

    J'ai fait un petit code qui additionne un array de float.

    %include "io64.inc"
    extern printf
    
    section .data
        array dd 1.225, 5.332, 10.32, 132.0
        format db "%5.5f", 0
        result dq 0
    section .bss
    
    
    section .text
    global CMAIN
    CMAIN:
        mov rbp, rsp; for correct debugging
        ;write your code here
        mov rax, 3
        fld dword [array+rax*4]
        dec rax
    ADDER:
        fld dword [array+rax*4]
        fadd 
        dec rax
        jns ADDER
        
        sub rsp, 8
        fstp qword [rsp]
        movq xmm0, [rsp]
        mov rdi, format
        mov al, 1
        call printf
        add rsp, 8
    
        ret

    J'aurai aimer comprendre 2 petites chose.

    1/ j'ai du mal a trouver mes instructions :s du coup j'ai fait :

        sub rsp, 8
        fstp qword [rsp]
        movq xmm0, [rsp]

    Je me demandais si il ni avait pas moyen de directement transferer le st0 dans le xmm0 sans avoir a sub 8 byte a la stack.

    2/ si je fait :

        sub rsp, 8
        fstp qword [rsp]
        movq xmm0, [rsp]
        add rsp, 8 ;<--- ici
        mov rdi, format
        mov al, 1
        call printf
        ;add rsp, 8 <---ici

    La fonction printf ne fonctionne plus. Du coup je me demande pour quoi la fonction printf a besoin de 8 byte de stack pour fonctionner

    :)

    • Partager sur Facebook
    • Partager sur Twitter

    "Etre vrai, peu le peuvent."
    Friedrich Nietzsche

      5 juillet 2021 à 7:31:53

      Il faut savoir que sur le x86 , le FPU de base est mal branlé , pour ça que depuis qu'il y'a eu l'extension x64 , le FPU n'est plus utilisé et on utilise les instructions SIMD pour faire des calcul de float  (avec addss , subss etc etc ).
      Pour ça que printf prend en argument xmm0 et non st0.

      Bon perso je trouve une grosse partie du x86 mal foutu dans son ensemble :p

      -
      Edité par HelbaSama 5 juillet 2021 à 7:34:43

      • Partager sur Facebook
      • Partager sur Twitter
        5 juillet 2021 à 14:58:35

        Hello

        Merci pour tes préconisation :) tu déconseils donc toutes les instructions utilisant l'accumulateur st ?

        -
        Edité par -Crixus- 5 juillet 2021 à 15:03:18

        • Partager sur Facebook
        • Partager sur Twitter

        "Etre vrai, peu le peuvent."
        Friedrich Nietzsche

          5 juillet 2021 à 15:12:25

          Oui je le déconseille , dejà qu'elle n'était pas top à l'époque (on faisait déjà mieux sur du MIPS ou du PowerPc) mais avec le temps c'est devenu des instructions complètement obsolètes :)
          Je pense qu'Intel ou AMD n'optimise même plus cette partie là , donc ils doivent eux aussi déconseillé d'utiliser ces instructions.
          • Partager sur Facebook
          • Partager sur Twitter
            5 juillet 2021 à 18:05:19

            Super.

            Merci pour les instructions (SIMD pour faire des calcul de float  (avec addss , subss etc etc ).)

            • Partager sur Facebook
            • Partager sur Twitter

            "Etre vrai, peu le peuvent."
            Friedrich Nietzsche

              5 juillet 2021 à 20:33:50

              Bonsoir.

              La fonction C printf n'a pas besoin de 8 octets de la pile pour fonctionner et l'explication est la suivante:

              En 64 bits, la pile doit toujours être alignée sur une frontière de 16 octets or dans le premier cas tu enlèves 8 octets sur le pointeur de pile avec l'instruction sub rsp,8 et le call à la fonction printf (ou à n'importe quelle autres fonctions) enlève aussi 8 octets au pointeur de pile pour stocker l'adresse de retour. Donc soustraction de 16 octets : la pile est toujours alignée. Après printf, le dépilement de l'adresse de retour ajoute 8 octets à la pile et ton instruction add rsp,8 aussi  soit 16 octets donc la pile est toujours alignée.

              Dans le cas qui ne fonctionne pas, tu enlèves 8 octets puis tu les ajoutes ce qui revient à 0 de décalage mais le call printf enlève 8 octets dont la pile est décalée de 8 octets et le programme crashes !!

              Tu pourras le vérifier sur d'autres appels de fonctions !! Et en plus si tu passes des paramètres par la pile, il faut tenir compte des push effectués.

              • Partager sur Facebook
              • Partager sur Twitter
                5 juillet 2021 à 23:40:23

                Merci pour ta réponse.

                Je suis passé a coté de cette info. Pour moi sachant que les adresses étaient sur 64bit l'alignement était sur 8 bytes et non 16 bytes.

                genre si je fais

                push al -> je suis pas aligné et je doit donc faire sub rsp 7

                si je fait push rax -> je suis aligné rien a faire.

                apparement c'est pas aussi simple :)

                Je suppose donc que c'est pour ca que sur ghidra quand je décompile du c sur certain début de fonction il me fait un :

                sub rsp, 0x8

                call push l'adresse de retour, du coup il push 8 bytes et il faut réaligner la stack avec 8 bytes supplémentaire ? ce qui est bizarre c'est qu'il me le fait pas sur toute les fonctions. Peut être uniquement sur celle qui on besoin d'avoir leurs stack aligné. En tout cas merci pour ce rappel. Ca a l'air important.

                -
                Edité par -Crixus- 6 juillet 2021 à 4:51:15

                • Partager sur Facebook
                • Partager sur Twitter

                "Etre vrai, peu le peuvent."
                Friedrich Nietzsche

                  6 juillet 2021 à 15:30:47

                  Pour le push al, je ne pense pas qu'en 64 bits il soit possible de ne stocker qu'un octet.

                  Je pense que le compilateur la remplace par un push rax et qui utilise 8 octets.

                  Mais à vérifier !

                  • Partager sur Facebook
                  • Partager sur Twitter
                    6 juillet 2021 à 16:37:03

                    PaulDurelin a écrit:

                    Pour le push al, je ne pense pas qu'en 64 bits il soit possible de ne stocker qu'un octet.

                    Je pense que le compilateur la remplace par un push rax et qui utilise 8 octets.

                    Mais à vérifier !

                    push al stocke bien 1 octet :)
                    C'est assez simple :
                    les données 8 bits n'ont pas besoin d’être aligné
                    les données 16 bits ont un alignement de 2 octets
                    les données 32 bits ont un alignement de 4 octets
                    les données 64 bits ont un alignement de 8 octets

                    Après que la pile a besoin d'un alignement de 16 octets , ça semble plus un besoin software que hardware.

                    Tu peux très bien push + appel de fonction sur autre chose qu'un alignement 16 octets, et ça marchera très bien ;)


                    • Partager sur Facebook
                    • Partager sur Twitter
                      6 juillet 2021 à 20:16:49

                      "Tu peux très bien push + appel de fonction sur autre chose qu'un alignement 16 octets, et ça marchera très bien"

                      Non, si la fonction est une fonction écrite en C dans une bibliothèque externe, cela ne fonctionnera pas !!

                      De plus le push al n'est pas autorisé par nasm sur un système windows 10 64 bits :

                      la preuve :

                      testpush64.asm:46: error: invalid combination of opcode and operands

                      • Partager sur Facebook
                      • Partager sur Twitter
                        7 juillet 2021 à 6:17:04

                        "Non, si la fonction est une fonction écrite en C dans une bibliothèque externe, cela ne fonctionnera pas !!"

                        Oui pour ça que j'ai dit que c'est une contrainte software et non hardware ;)

                        Et c'était donc pour répondre à ceci :
                        "Je suis passé a coté de cette info. Pour moi sachant que les adresses étaient sur 64bit l'alignement était sur 8 bytes et non 16 bytes."
                        Et il a raison en 64 bits on a un alignement de 8 octets :)


                        Pour push al , ça ne marche pas c'est vrai autant pour moi , mais ça ne semble pas marcher aussi en non 64 bits !
                        Vu que l'instruction ne semble pas existé :
                        https://www.felixcloutier.com/x86/push

                        Ce qui est logique de base le x86 est un proc 16 bits donc le minimum est de push 16 bits.
                        (Mais le push 32 bits disparaît du coup en 64 bits )

                        -
                        Edité par HelbaSama 7 juillet 2021 à 10:10:41

                        • Partager sur Facebook
                        • Partager sur Twitter
                          7 juillet 2021 à 13:26:23

                          si je dis que l'alignement est sur 8bytes en 64bits c'est que de ce que j'ai compris les bus mémoire et donné font 64bits et que le "but" de l'alignement est d'utiliser le moins de commande lecture/ecriture.

                          en effet pour les bit pas d'alignement. mais si on a 2bytes a lire et que c'est 2 byte commencent sur un offset de 7bytes alors il faudra 2 lectures.

                          • Partager sur Facebook
                          • Partager sur Twitter

                          "Etre vrai, peu le peuvent."
                          Friedrich Nietzsche

                            9 juillet 2021 à 3:09:38

                            Alors je vais foutre un peu la merde :)

                            C'est bien 16bytes d'alignement la norme sur x64 et 8bytes sur x86 pour la stack :)

                            https://docs.microsoft.com/en-us/cpp/build/stack-usage?view=msvc-160

                            Ce qui est dommage c'est qu'ils ne donnent pas la raison physique a cette norme. Si ils la donnent je ne l'ai pas vu. Sa me parait même faux leurs raisonnement a moins que des système x64 aient des bus mémoire de plus de 8bytes ? et a moins que j'ai mal compris, ca a l'air d'être leur explication :

                            The stack will always be maintained 16-byte aligned, except within the prolog (for example, after the return address is pushed), and except where indicated in Function Types for a certain class of frame functions.

                            malloc alignment

                            malloc is guaranteed to return memory that's suitably aligned for storing any object that has a fundamental alignment and that could fit in the amount of memory that's allocated. A fundamental alignment is an alignment that's less than or equal to the largest alignment that's supported by the implementation without an alignment specification. (In Visual C++, this is the alignment that's required for a double, or 8 bytes. In code that targets 64-bit platforms, it's 16 bytes.) For example, a four-byte allocation would be aligned on a boundary that supports any four-byte or smaller object.

                            -
                            Edité par -Crixus- 9 juillet 2021 à 3:17:48

                            • Partager sur Facebook
                            • Partager sur Twitter

                            "Etre vrai, peu le peuvent."
                            Friedrich Nietzsche

                            assembleur addition float

                            × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                            • Editeur
                            • Markdown