Pregunta

Estoy usando Borland Turbo C ++ con un código de ensamblador en línea, por lo que presumiblemente el código de ensamblaje de estilo Turbo Assembler (TASM). Deseo hacer lo siguiente:

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

Entonces, la dirección de SomeLabel se coloca en EAX. Esto no funciona y el compilador se queja de: Símbolo indefinido 'SomeLabel'.

En Microsoft Assembler (MASM), el símbolo del dólar ($) sirve como el contador de ubicación actual, lo que sería útil para mi propósito. Pero, de nuevo, esto no parece funcionar en Borlands Assember (error de sintaxis de expresión).

Actualización: para ser un poco más específico, necesito que el compilador genere la dirección en la que se mueve eax como constante durante la compilación / vinculación y no en tiempo de ejecución, por lo que se compilará como '' mov eax, 0x00401234 ''.

¿Alguien puede sugerir cómo hacer que esto funcione?

ACTUALIZACIÓN: para responder a la pregunta de Pax (ver comentario), si el cargador de Windows cambia la dirección base en tiempo de ejecución, el cargador de Windows reubicará la imagen DLL / EXE PE y la dirección de las etiquetas se parcheará en tiempo de ejecución por el cargador para usar la dirección basada de nuevo, por lo que usar un valor de tiempo de compilación / enlace para la dirección de la etiqueta no es un problema.

Muchas gracias de antemano.

¿Fue útil?

Solución

La última vez que intenté hacer un código de ensamblaje compatible con Borland, me encontré con la limitación de que no puedes reenviar las etiquetas. No estoy seguro si eso es con lo que te estás encontrando aquí.

Otros consejos

Todo lo que puedo encontrar sobre Borland sugiere que esto debería funcionar. Preguntas similares en otros sitios ( aquí y aquí ) sugiere que Borland puede manejar referencias directas para etiquetas, pero insiste en las etiquetas están fuera de los bloques asm. Sin embargo, como su etiqueta ya estaba fuera del bloque asm ...

Tengo curiosidad por saber si su compilador le permitiría usar esta etiqueta dentro de, por ejemplo, una instrucción jmp. Al jugar con él (es cierto, en un compilador completamente diferente), encontré una tendencia molesta para que el compilador se quejara de los tipos de operandos.

La sintaxis es bastante diferente, y es mi primer intento de asm en línea en mucho tiempo, pero creo que he usado esto lo suficiente como para trabajar bajo gcc. Quizás, a pesar de las diferencias, esto podría serle útil:

#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;
}

Esto genera:

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

El & amp; & amp; El operador es una extensión no estándar, no esperaría que funcione en otro lugar que no sea gcc. Esperemos que esto haya despertado algunas ideas nuevas ... ¡Buena suerte!

Editar: aunque aparece como específico de Microsoft, aquí está otra instancia de saltar a las etiquetas.

3 sugerencias:

1) ponga un '_' delante de SomeLabel en el ensamblaje para que se convierta en '' mov eax, _SomeLabel " ;. Por lo general, el compilador agregará uno cuando traduzca C en ensamblaje.

O

2) coloque la etiqueta en una sección de ensamblaje. Esto evitará que el compilador agregue '_'.

O

3) comente el ensamblaje, compile y mire en el archivo de listado (* .lst) para ver en qué se convierte el nombre de la etiqueta.

¿El entorno Turbo C ++ tiene una forma de establecer opciones para TASM (sé que algunos de los IDE de Borland sí lo hicieron)?

Si es así, vea si cambia la opción para " Pases máximos (/ m) " a 2 o más ayudas (puede ser predeterminado a 1 pase).

Además, si está utilizando un nombre de etiqueta largo que podría plantear un problema, al menos un IDE tenía el valor predeterminado establecido en 12. Cambie la opción " Longitud máxima del símbolo (/ mv) " ;.

Esta información se basa en el IDE RAD Studio de Borland:

Un par de cosas más (disparos en la oscuridad) para probar:

  • vea si ayuda con las siguientes instrucciones de ensamblaje:

    mov eax, offset SomeLabel
    
  • la mayoría de los compiladores pueden producir una lista de ensamblaje del código que generan (no estoy seguro si Turbo C ++ puede hacerlo, ya que Codegear / Embarcadero lo posiciona como un compilador gratuito y no profesional).

    Intente producir un listado con código C que tenga una etiqueta de usos (como un destino goto por ejemplo), con algún ensamblaje en línea en la misma función, pero no intente acceder a la etiqueta de la asamblea. Esto es para que pueda obtener un compilador sin errores y una lista de ensamblaje. Algo así como:

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

    Mire la lista de ensamblajes y vea si el ensamblaje generado decora el nombre de la etiqueta de una manera que pueda replicar en el ensamblaje en línea.

Por lo que recuerdo, no puede usar una etiqueta externa (C ++) en su ensamblaje en línea, aunque puede tener etiquetas de estilo TASM en el bloque asm a las que las instrucciones de ensamblaje pueden hacer referencia. Creo que usaría una bandera y una declaración de cambio posterior al ensamblador para manejar la ramificación. Por ejemplo:

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;
}

No sé sobre su compilador / ensamblador específicamente, pero un truco que he usado bastante es llamar a la siguiente ubicación y luego colocar la pila en su registro. Asegúrese de que la llamada que realiza solo empuje la dirección del remitente.

Creo que el problema con el que te encuentras es que una etiqueta dentro del bloque __asm ?? y la etiqueta en el código C ++ son dos cosas completamente diferentes. No esperaría que pudieras hacer referencia a una etiqueta C ++ de esa manera desde el ensamblaje en línea, pero debo decir que ha pasado mucho tiempo desde que usé Turbo C ++.

¿Has probado la instrucción lea en lugar de mov ?

Solo adivinando ya que no he usado el ensamblador en línea con ningún compilador de C / ++ ...

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

No sé la sintaxis exacta de TASM.

Esta es una variante de la sugerencia de Ivan, pero inténtalo:

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

Aquí hay un posible método:

// 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;
}

Es un poco hacky pero funciona en la versión de Turbo C ++ que tengo. Es casi seguro que depende de la configuración del compilador y la optimización.

una de las opciones sería usar por separado "desnudo" (sin prólogo) procedimiento SomeLabel en lugar de etiqueta

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top