Pregunta

Si desea llamar a la función de C / C ++ de la línea de ensamblaje, puede hacer algo como esto:

void callee() {}
void caller()
{
    asm("call *%0" : : "r"(callee));
}

GCC entonces emitir un código que será la siguiente:

movl $callee, %eax
call *%eax

Esto puede ser problemático ya que la llamada indirecta destruirá la tubería en las CPU de mayor edad.

Desde la dirección de callee es, finalmente, una constante, uno puede imaginar que sería posible utilizar la restricción i. Citando del CCG en línea docs :

  

`i '

     se permite

Un operando número entero inmediata (una con valor constante). Esta   incluye constantes simbólicas cuya   valores serán conocidos solamente en conjunto   tiempo o más tarde.

Si trato de utilizar de esta manera:

asm("call %0" : : "i"(callee));

Me sale el siguiente error desde el ensamblador:

  

Error: sufijo o operandos no válido para `llamada '

Esto se debe a GCC emite el código

call $callee

En lugar de

call callee

Así que mi pregunta es si es posible hacer que la salida del CCG call correcta.

¿Fue útil?

Solución

de la lista de correo de GCC :

asm("call %P0" : : "i"(callee));

Ahora sólo tengo que averiguar lo que en realidad significa %P0, ya que parece ser una característica no documentada ...

Editar : Después de ver el código fuente de GCC, no está claro exactamente lo que el código de P frente a un medio de restricción. Pero, entre otras cosas, impide GCC de poner un $ frente a valores constantes. Que es exactamente lo que necesito en este caso.

Otros consejos

Tal vez me estoy perdiendo algo aquí, pero

extern "C" void callee(void) 
{

}

void caller(void)
{
  asm("call callee\n");
}

debería funcionar bien. Usted necesita extern "C", por lo que el nombre no será decorada basa en C ++ reglas de denominación mangling.

El truco es concatenación de cadenas literales. Antes de GCC comienza tratando de obtener un significado real a partir del código que será concatenar cadenas literales adyacentes, por lo que a pesar de que el montaje cadenas no son lo mismo que otras cadenas que utiliza en su programa deben ser concatenadas si lo hace:

#define ASM_CALL(X) asm("\t call  " X "\n")


int main(void) {
    ASM_CALL( "my_function" );
    return 0;
}

Desde que está utilizando GCC también se puede hacer

#define ASM_CALL(X) asm("\t call  " #X "\n")

int main(void) {
   ASM_CALL(my_function);
   return 0;
}

Si no lo sabe ya que debe ser consciente de que llamar a las cosas de la línea de montaje es muy complicado. Cuando el compilador genera sus propias llamadas a otras funciones que incluye código para configurar y restaurar las cosas antes y después de la llamada. No sabe que debería estar haciendo nada de esto por su llamada, sin embargo. Tendrá que o bien incluir que usted mismo (muy difícil de hacerlo bien y puede romper con una actualización compilador o compilación banderas) o asegurarse de que su función se escribe de tal manera que no parece haber cambiado de cualquier registro o condición de la pila (o variable en él).

editar esto sólo funcionará para los nombres de las funciones C -. No C ++, ya que están destrozados

Si se está generando código de 32 bits (por ejemplo -m32 gcc opción), la siguiente línea asm emite una llamada directa:

asm ("call %0" :: "m" (callee));
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top