Question

J'utilise Borland Turbo C ++ avec du code assembleur intégré, donc probablement du code assembleur de style Turbo Assembler (TASM). Je souhaite faire ce qui suit:

void foo::bar( void )
{
    __asm
    {
      mov eax, SomeLabel
      // ...
    }
    // ...
SomeLabel:
    // ...
}

L’adresse de SomeLabel est donc placée dans EAX. Cela ne fonctionne pas et le compilateur se plaint de: symbole indéfini 'SomeLabel'.

Dans Microsoft Assembler (MASM), le symbole dollar ($) sert de compteur d’emplacement actuel, ce qui me serait utile. Mais encore une fois, cela ne semble pas fonctionner dans Borlands Assember (erreur de syntaxe d'expression).

Mise à jour: Pour être un peu plus spécifique, j'ai besoin que le compilateur génère l'adresse qu'il déplace dans eax sous forme de constante lors de la compilation / liaison et non au moment de l'exécution, il sera donc compilé comme suit: "mov eax, 0x00401234".

Quelqu'un peut-il suggérer comment faire fonctionner cela?

UPDATE: pour répondre à la question de Pax (voir le commentaire), si l'adresse de base est modifiée à l'exécution par le chargeur Windows, l'image de DLL / EXE PE sera toujours déplacée par le chargeur Windows et l'adresse des étiquettes sera corrigée à Pour que le chargeur puisse utiliser l’adresse de recalage, l’utilisation d’une valeur d’heure de compilation / liaison pour l’adresse de l’étiquette n’est pas un problème.

Merci d'avance.

Était-ce utile?

La solution

La dernière fois que j'ai essayé de rendre compatible un code d'assemblage compatible avec Borland, je suis tombé sur une limitation qui empêchait l'envoi d'étiquettes de référence. Je ne sais pas si c'est ce que vous rencontrez ici.

Autres conseils

Tout ce que je peux trouver sur Borland suggère que cela devrait fonctionner. Des questions similaires sur d'autres sites ( ici et here ) suggèrent que Borland peut gérer les références en aval pour les libellés, mais insiste sur le fait les étiquettes étant en dehors des blocs asm. Cependant, comme votre étiquette était déjà en dehors du bloc asm ...

Je suis curieux de savoir si votre compilateur vous autoriserait à utiliser cette étiquette dans, par exemple, une instruction jmp. En jouant avec elle (certes, sur un compilateur complètement différent), j'ai trouvé une tendance embêtante pour le compilateur à se plaindre des types d'opérandes.

La syntaxe est assez différente, et c’est ma première tentative d’inline inm depuis longtemps, mais je pense que j’en ai assez appris à fonctionner sous gcc. Peut-être, malgré les différences, cela pourrait vous être utile:

#include <stdio.h>
int main()
{
    void *too = &&SomeLabel;
    unsigned int out;
    asm
    (
      "movl %0, %%eax;"
      :"=a"(out)
      :"r"(&&SomeLabel)
    );
SomeLabel:
    printf("Result: %p %x\n", too, out);

    return 0;
}

Ceci génère:

...
        movl    $.L2, %eax
...
.L2:

Le & amp; & amp; L’opérateur est une extension non standard, je ne pense pas que cela fonctionne ailleurs que gcc. J'espère que cela a suscité de nouvelles idées ... Bonne chance!

Modifier: bien que répertorié comme spécifique à Microsoft, ici est une autre instance de saut aux étiquettes.

3 suggestions:

1) placez un '_' devant le SomeLabel dans l'assemblage pour qu'il devienne "mov eax, _SomeLabel " ;. Habituellement, le compilateur en ajoute un lorsqu'il convertit C en assembleur.

Ou

2) placez l'étiquette dans une section d'assemblage. Cela empêchera le compilateur d’ajouter le '_'.

Ou

3) commentez l'assembly, compilez-le et regardez dans le fichier de liste (* .lst) pour voir le nom de l'étiquette.

L’environnement Turbo C ++ permet-il de définir des options pour TASM (je sais que certains des IDE de Borland l’avaient déjà fait)?

Si tel est le cas, vérifiez si l'option est définie sur "Nombre maximal de passes (/ m)". à 2 ou plus aide (il peut par défaut à 1 passage).

De même, si vous utilisez un nom de libellé long qui pourrait poser problème, par défaut, au moins un IDE a été défini sur 12. Modifiez l'option "Longueur maximale du symbole (/ mv)".

Ces informations sont basées sur l'EDI de RAD Studio de Borland:

Encore quelques choses à essayer (photos dans le noir):

  • voyez si l'aide de l'instruction d'assemblage suivante vous aide:

    mov eax, offset SomeLabel
    
  • la plupart des compilateurs peuvent produire une liste d'assemblage du code qu'ils génèrent (je ne sais pas si Turbo C ++ peut le faire, car Codegear / Embarcadero le positionne comme un compilateur gratuit et non professionnel).

    Essayez de produire une liste avec du code C qui utilise une étiquette (par exemple, une cible goto ), avec un assemblage en ligne ayant la même fonction - mais n'essayez pas d'accéder à l'étiquette. de l'assemblée. Cela vous permet d’obtenir un compilateur sans erreur et une liste d’assemblages. Quelque chose comme:

    int foo()
    {
        int x = 3;
        printf( "x =%d\n", x);
        goto SomeLabel;
                               //
        __asm {
            mov eax, 0x01
        }
                               //
    SomeLabel:
        printf( "x =%d\n", x);
                               //
        return x;
    }
    

    Consultez la liste des assemblages pour voir si l'assemblage généré décore le nom de l'étiquette de manière à pouvoir être répliqué dans l'assemblage en ligne.

D'après mes souvenirs, vous ne pouvez pas utiliser d'étiquette externe (C ++) dans votre assemblage en ligne, bien que vous puissiez avoir des étiquettes de style TASM dans le bloc asm pouvant être référencées par les instructions d'assemblage elles-mêmes. Je pense que j'utiliserais un indicateur et une instruction switch post-assembler pour gérer les branches. Par exemple:

int result=0;

__asm__ {
    mov result, 1
}

switch (result){
    case 1:  printf("You wanted case 1 to happen in your assembler\n"); break;
    case 0:  printf("Nothing changed with the result variable.. defaulting to:\n");
    default: printf("Default case!\n"); break;
}

Je ne connais pas spécifiquement votre compilateur / assembleur, mais une astuce que j'ai un peu utilisée consiste à appeler l'emplacement suivant, puis à insérer la pile dans votre registre. Assurez-vous que l'appel que vous effectuez ne fait que pousser l'adresse de retour.

Je pense que le problème que vous rencontrez est qu'une étiquette à l'intérieur du bloc __ asm et l'étiquette dans le code C ++ sont deux choses complètement différentes. Je ne m'attendrais pas à ce que vous puissiez référencer une étiquette C ++ de cette manière à partir d'un assemblage en ligne, mais je dois dire que cela fait très longtemps que je n'ai pas utilisé Turbo C ++.

Avez-vous essayé l'instruction lea au lieu de mov ?

Je suppose que je n'ai pas utilisé d'assembleur inline avec un compilateur C / ++ ...

void foo::bar( void )
{
    __asm
    {
      mov eax, SomeLabel
      // ...
    }
    // ...
    __asm
    {
      SomeLabel:
      // ...
    }
    // ...
}

Je ne connais pas la syntaxe exacte de TASM.

C’est une variante de la suggestion d’Ivan, mais essayez-la:

void foo::bar( void )
{
    __asm
    {
      mov eax, offset SomeLabel
      // ...
    }
    // ...
    __asm SomeLabel:
    // ...
}

Voici une méthode possible:

// get_address
// gets the address of the instruction following the call
// to this function, for example
//     int addr = get_address (); // effectively returns the address of 'label'
//   label:
int get_address ()
{
    int address;
    asm
    {
        mov eax,[esp+8]
        mov address,eax
    }
    return address;
}
// get_label_address
// a bit like get_address but returns the address of the instruction pointed
// to by the jmp instruction after the call to this function, for example:
//     int addr;
//     asm
//     {
//       call get_label_address // gets the address of 'label'
//       jmp label
//       mov addr,eax
//     }
//     <some code>
//   label:
// note that the function should only be called from within an asm block.
int get_label_address()
{
    int address = 0;
    asm
    {
        mov esi,[esp+12]
        mov al,[esi]
        cmp al,0ebh
        jne not_short
        movsx eax,byte ptr [esi+1]
        lea eax,[eax+esi-1]
        mov address,eax
        add esi,2
        mov [esp+12],esi
        jmp done
    not_short:
        cmp al,0e9h
        jne not_long
        mov eax,dword ptr [esi+1]
        lea eax,[eax+esi+2]
        mov address,eax
        add esi,5
        mov [esp+12],esi
        jmp done
    not_long:
        // handle other jmp forms or generate an error
    done:
    }
    return address;
}
int main(int argc, char* argv[])
{
    int addr1,addr2;
    asm
    {
        call get_label_address
        jmp Label1
        mov addr1,eax
    }

    addr2 = get_address ();
Label1:
    return 0;
}

C’est un peu hacky mais cela fonctionne dans la version de Turbo C ++ que je possède. Cela dépend presque certainement du compilateur et des paramètres d'optimisation.

L’une des options consisterait à utiliser des options distinctes "nue". (prolog-less) procedure SomeLabel au lieu de label

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top