c++ - maquina - programas en lenguaje ensamblador explicados
Ensamblador en línea Borland x86; obtener la dirección de una etiqueta? (12)
¿El entorno de Turbo C ++ tiene una forma de establecer opciones para TASM (sé que algunos de los IDEs de Borland lo hicieron)?
Si es así, ver si cambiar la opción de "Máximo de pases (/ m)" a 2 o más ayuda (puede ser de manera predeterminada 1 pase).
Además, si usa 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 RAD Studio IDE de Borland:
Estoy usando Borland Turbo C ++ con un código ensamblador en línea, por lo que presumiblemente el código ensamblador 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 no definido ''SomeLabel''.
En Microsoft Assembler (MASM), el símbolo de dólar ($) sirve como el contador de ubicación actual, 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 una constante durante la compilación / vinculación y no en el tiempo de ejecución, por lo que se compilará como "mov eax, 0x00401234".
¿Alguien puede sugerir cómo hacerlo funcionar?
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, la cargadora de Windows reubicará la imagen DLL / EXE PE y la dirección de las etiquetas será parcheada en tiempo de ejecución por el cargador para usar la dirección re-basada así 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.
3 sugerencias:
1) coloque un ''_'' delante de SomeLabel en el conjunto 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 el ''_''.
O
3) comente el ensamblaje, compile y busque en el archivo de la lista (* .lst) para ver en qué se convierte el nombre de la etiqueta.
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 raro, 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.
Creo que el problema al que te estás __asm
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 pudiera hacer referencia a una etiqueta C ++ de ese modo desde el ensamblaje en línea, pero debo decir que ha pasado mucho tiempo desde que utilicé Turbo C ++.
¿Has probado la instrucción lea
lugar de mov
?
Esta es una variante de la sugerencia de Iván, pero intenta esto:
void foo::bar( void )
{
__asm
{
mov eax, offset SomeLabel
// ...
}
// ...
__asm SomeLabel:
// ...
}
La última vez que traté de hacer un código de ensamblaje compatible con Borland encontré la limitación de que no se pueden reenviar las etiquetas de referencia. No estoy seguro si eso es lo que te encuentras aquí.
No sé específicamente sobre tu compilador / ensamblador, pero un truco que he usado bastante es llamar a la siguiente ubicación y luego colocar la pila en tu registro. Asegúrese de que la llamada que realiza solo presione la dirección de retorno.
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 un indicador y una instrucción de cambio post ensamblador para manejar la bifurcació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;
}
Simplemente 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.
Todo lo que puedo encontrar sobre Borland sugiere que esto debería funcionar. Preguntas similares en otros sitios ( aquí y aquí ) sugieren que Borland puede manejar referencias futuras para etiquetas, pero insiste en que las etiquetas estén fuera de los bloques de asm. Sin embargo, como su etiqueta ya estaba fuera del bloque asm ...
Tengo curiosidad de si su compilador le permite usar esta etiqueta dentro de, por ejemplo, una instrucción jmp. Cuando jugaba con eso (ciertamente, en un compilador completamente diferente), encontré una tendencia molesta para el compilador a quejarse sobre 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 cometido esto suficiente para trabajar bajo gcc. Tal vez, a pesar de las diferencias, esto podría ser de alguna utilidad para usted:
#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 operador && es una extensión no estándar, no esperaría que funcione en otro lugar que no sea gcc. Espero que esto haya despertado algunas ideas nuevas ... ¡Buena suerte!
Editar: Aunque aparece como específico de Microsoft, aquí hay otra instancia de saltar a las etiquetas.
Un par de cosas más (disparos en la oscuridad) para intentar:
ver si usar las siguientes instrucciones de ensamblaje ayuda:
mov eax, offset SomeLabel
la mayoría de los compiladores pueden producir una lista de ensamblaje del código que generan (no estoy seguro de si Turbo C ++ puede hacerlo, ya que Codegear / Embarcadero lo posiciona como un compilador gratuito y no profesional).
Intente producir una lista con código C que tenga una etiqueta (por ejemplo, un objetivo
goto
), con un ensamblaje en línea en la misma función, pero no intente acceder a la etiqueta desde el ensamblaje. Esto es para que pueda obtener un compilador sin errores y una lista de ensamblado. Algo 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 ensambles y vea si el ensamblaje generado decora el nombre de la etiqueta de forma que pueda replicar en el ensamblado en línea.
una de las opciones sería usar el procedimiento separado "sin etiquetas" (sin prólogo) SomeLabel en lugar de la etiqueta