Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Lazarus Pascal Discussion :

Insérer de l'assembleur dans Lazarus


Sujet :

Lazarus Pascal

  1. #1
    Membre du Club
    Insérer de l'assembleur dans Lazarus
    Bonjour,
    J'utilisais Delphi et j'essaie d'utiliser maintenant Lazarus. Dans Delphi, je savais insérer directement de l'assembleur en commençant par asm.
    Cela génère une erreur dans Lazarus.
    Y a-t-il une solution ?
    merci

  2. #2
    Modérateur

    Bonjour, je lis ici :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
      //This is required with Lazarus on x86:
      {$ASMMODE intel}

    Est-ce une piste ?
    Delphi 5 Pro - Delphi 10.3.2 Rio Community Edition - CodeTyphon 6.90 sous Windows 10 ; CT 6.40 sous Ubuntu 18.04 (VM)
    . Ignorer la FAQ Delphi et les Cours et Tutoriels Delphi nuit gravement à notre code !

  3. #3
    Expert éminent sénior
    Bonjour,

    pour compléter ce que dit tourlourou (), je donne une fonction complète :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function Swap32_si_Moto(C : Cardinal) : Cardinal;
    var
     S : Cardinal;
    begin
      {$ASMMODE intel} // nécessaire si pas {$mode delphi} + couple begin/end
      asm
        bswap EAX // C est passé dans EAX et bswap échange les octets 0123 -> 3210
        mov   S, EAX
      end;
      if Motorola then Result := S else Result := C;
    end;


    et je rajoute
    Citation Envoyé par GerardJ Voir le message
    Cela génère une erreur dans Lazarus.
    qu'une bonne pratique sur les forums consiste à donner l'erreur, sinon on perd du temps à poser la question "et c'est quoi l'erreur ?" puis à attendre la réponse, ici ça allait, c'était facile.
    Il a à vivre sa vie comme ça et il est mûr sur ce mur se creusant la tête : peutêtre qu'il peut être sûr, etc.
    Oui, je milite pour l'orthographe et le respect du trait d'union à l'impératif.
    Après avoir posté, relisez-vous ! Et en cas d'erreur ou d'oubli, il existe un bouton « Modifier », à utiliser sans modération
    On a des lois pour protéger les remboursements aux faiseurs d’argent. On n’en a pas pour empêcher un être humain de mourir de misère.
    Mes 2 cts,
    --
    jp

  4. #4
    Membre expert
    Bonjour

    Il y a deux methodes pour utiliser l'assembleur

    Comme l'ont dit mes compères :
    Tu places la directive

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    Unit Unit1;
     
    {$mode objfpc}{$H+} 
    {$asmmode intel} // si non par defaut c'est le mode ATT&T. Voir aussi dans les options du projet
     
    Interface


    1) Tu souhaites imbriquer de l'assembleur dans du code natif

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    procedure DoSomething;
    var
     i: integer
    begin
      for i:= 0 to 9 do
      begin
        asm
           // ton code asm ici
        end;
      end;
    end;


    2) Tu souhaites créer une procedure ou fonction entièrement en assembleur
    Il faut alors utiliser le mot clef assembler

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    function doSomething : byte; assembler;
    asm
      // ton code assembleur ici
    end;
     
    procedure doSomething; assembler;
    asm
      // ton code assembleur ici
    end;


    voir :
    https://wiki.freepascal.org/Asm
    https://wiki.freepascal.org/Assemble..._ABI_Resources

    Tu disposes en plus du mot clef assembler de : Register, nostackframe et vectorcall ce dernier étant dispo uniquement à partir de FPC 3.2 et uniquement pour Windows et les instructions SIMD

    exemple :

    pour Windows et avec FPC 3.0.4

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    function TBZVector4f.DivideBy2:TBZVector4f;assembler; nostackframe; register;
    asm
      movaps xmm0,[RCX]
      mulps xmm0, XMMWORD PTR [RIP+cHalfOneVector4f]
      movaps [RESULT],xmm0
    end;


    pour Windows et avec FPC 3.2 (non testé)
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    function TBZVector4f.DivideBy2:TBZVector4f;assembler; vectorcall;
    asm
      mulps xmm0, XMMWORD PTR [RIP+cHalfOneVector4f]
      movaps [RESULT],xmm0 
    end;


    A+

    Jérôme
    • "L'Homme devrait mettre autant d'ardeur à simplifier sa vie qu'il met à la compliquer" - Henri Bergson
    • "Bien des livres auraient été plus clairs s'ils n'avaient pas voulu être si clairs" - Emmanuel Kant
    • "La simplicité est la sophistication suprême" - Léonard De Vinci
    • "Ce qui est facile à comprendre ou à faire pour toi, ne l'est pas forcément pour l'autre." - Mon pèrei

    Mes projets sur Github - Blog - Site DVP

  5. #5
    Membre du Club
    Citation Envoyé par Jipété Voir le message
    Bonjour,

    pour compléter ce que dit tourlourou (), je donne une fonction complète :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function Swap32_si_Moto(C : Cardinal) : Cardinal;
    var
     S : Cardinal;
    begin
      {$ASMMODE intel} // nécessaire si pas {$mode delphi} + couple begin/end
      asm
        bswap EAX // C est passé dans EAX et bswap échange les octets 0123 -> 3210
        mov   S, EAX
      end;
      if Motorola then Result := S else Result := C;
    end;


    et je rajoute

    qu'une bonne pratique sur les forums consiste à donner l'erreur, sinon on perd du temps à poser la question "et c'est quoi l'erreur ?" puis à attendre la réponse, ici ça allait, c'était facile.
    Merci ça marche sauf que cela génère une erreur que je n'ai pas dans Delphi...
    joueur.pas(391,8) Error: Asm: [push reg32] invalid combination of opcode and operands
    le code :
    Code asm :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
     
            MOV  EAX, Substr
            MOV  EDX, S
            MOV  ECX, &Offset
           test  eax, eax
           jz    @Nil
           test  edx, edx
           jz    @Nil
           dec   ecx
           jl    @Nil
     
           push  esi
           push  ebx
     
           mov   esi, [edx-4]  //Length(Str)
           mov   ebx, [eax-4]  //Length(Substr)
           sub   esi, ecx      //effective length of Str
           add   edx, ecx      //addr of the first char at starting position
           cmp   esi, ebx
           jl    @Past         //jump if EffectiveLength(Str)<Length(Substr)
           test  ebx, ebx
           jle   @Past         //jump if Length(Substr)<=0
     
           add   esp, -12
           add   ebx, -1       //Length(Substr)-1
           add   esi, edx      //addr of the terminator
           add   edx, ebx      //addr of the last char at starting position
           mov   [esp+8], esi  //save addr of the terminator
           add   eax, ebx      //addr of the last char of Substr
           sub   ecx, edx      //-@Str[Length(Substr)]
           neg   ebx           //-(Length(Substr)-1)
           mov   [esp+4], ecx  //save -@Str[Length(Substr)]
           mov   [esp], ebx    //save -(Length(Substr)-1)
           movzx ecx, byte ptr [eax] //the last char of Substr
     
    @Loop:
           cmp   cl, [edx]
           jz    @Test0
           jmp   @Exit
    @AfterTest0:
           cmp   cl, [edx+1]
           jz    @TestT
    @AfterTestT:
           add   edx, 4
           cmp   edx, [esp+8]
           jb   @Continue
    @EndLoop:
           add   edx, -2
           cmp   edx, [esp+8]
           jb    @Loop
    @Exit:
           add   esp, 12
    @Past:
           pop   ebx
           pop   esi
    @Nil:
           xor   eax, eax
           //ret
           jmp  @Fin
    @Continue:
           cmp   cl, [edx-2]
           jz    @Test2
           cmp   cl, [edx-1]
           jnz   @Loop
    @Test1:
           add   edx,  1
    @Test2:
           add   edx, -2
    @Test0:
           add   edx, -1
    @TestT:
           mov   esi, [esp]
           test  esi, esi
           jz    @Found
    @String:
           movzx ebx, word ptr [esi+eax]
           cmp   bx, word ptr [esi+edx+1]
           jnz   @Exit
           cmp   esi, -2
           jge   @Found
           movzx ebx, word ptr [esi+eax+2]
           cmp   bx, word ptr [esi+edx+3]
           jnz   @Exit
           add   esi, 4
           jl    @String
    @Found:
           mov   eax, [esp+4]
           add   edx, 2
     
           cmp   edx, [esp+8]
           ja    @Exit
     
           add   esp, 12
           add   eax, edx
           pop   ebx
           pop   esi
    @Fin:

  6. #6
    Membre du Club
    Ce sont les lignes 12 et 13 (push esi et push ebx) et les lignes pop correspondantes....

  7. #7
    Membre éclairé
    Bonjour GerardJ,

    Si tu compile pour une plateforme cible 64bits il est possible que tu ne puisse pas PUSHer/POPer des registres 32 bits, ce qui correspondrait bien au message d'erreur constaté.

    Essai de PUSHer/POPer RSI et RBX au lieu de ESI et EBX.

  8. #8
    Responsable Pascal, Lazarus et Assembleur

    Bonjour,

    Citation Envoyé par DomDA91 Voir le message
    Si tu compile pour une plateforme cible 64bits il est possible que tu ne puisse pas PUSHer/POPer des registres 32 bits, ce qui correspondrait bien au message d'erreur constaté.

    Essai de PUSHer/POPer RSI et RBX au lieu de ESI et EBX.
    Exactement, en 64 bits il est possible de pusher des registres 64 bits et 16 bits (moyennant préfixe) mais pas 32 bits.
    Règles du forum
    Cours et tutoriels Pascal, Delphi, Lazarus et Assembleur
    Avant de poser une question, consultez les FAQ Pascal, Delphi, Lazarus et Assembleur
    Mes tutoriels et sources Pascal

    Le problème en ce bas monde est que les imbéciles sont sûrs d'eux et fiers comme des coqs de basse cour, alors que les gens intelligents sont emplis de doute. [Bertrand Russell]

  9. #9
    Membre éclairé
    32 et 64 sont dans un bateau
    Bonjour,

    D'autres différences existent entre 32 et 64 bits comme l'usage des registres pour passer les arguments (il est préférable d'inciter explicitement le compilateur à utiliser les registres plutôt que la pile en ajoutant noframestack).

    Ainsi l'exemple swap sur intel passera effectivement l'argument dans eax en 32 bits mais pas dans rax en 64 bits (plutôt rdx). Ça n'aide pas la portabilité mais je crois que c'est pour respecter la convention de fastcall.

    Remarque : la multiplication du nombre de registres en 64 bits permet souvent d'éviter (ou de limiter) empilages et dépilages (push/pop) qui ne sont pas neutres en temps, surtout pour des fonctions courtes. Dans l'exemple, on peut ainsi remplacer esi et ebx par r10d et r11d et gagner ainsi 4 opérations push/pop.

    Toujours pour les fonctions/procédures courtes. Il faut éviter d'utiliser l'assembleur pour des opérations accessibles simplement au langage. En effet, un code standard autorisera un inline (inopérant avec du code assembleur) qui permettra au compilateur d'éviter tout appel/retour de fonction et lui laissera le loisir de jongler avec les registres (alors que l'assembleur fixe les registres utilisés). Bien sûr, il en est autrement si l'opération nécessite beaucoup plus de code Pascal que de code assembleur (si si ça existe): exemple popcnt qui compte le nombre de bits à 1 d'un registre.

    L'optimisation est un sport de combat

    Salutations
    Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better. (Samuel Beckett)