2011-08-10 17 views
6

quiero definir una función en el ensamblaje LLVM que toma como argumento:montaje LLVM: llamar a una función utilizando varargs

  • un identificador a un sub-función
  • un vararg

Este la función debe hacer un preprocesamiento, encontrar la función correcta para el identificador y llamarlo usando vararg, y devolver su resultado.

Algo así como:

define ??? @1 (i32 %identifier, ...vararg...) 
{ 
    switch i32 %identifier, label %def, i32 1, label %a 
a: 
    %1 = tail call @function_for_a, ...vararg... 
    ret ??? %1 
def: 
    ret void 
} 

No parece ser posible. ¿Hay alguna forma de hacer eso? Creo que debería ser posible usar un ensamblador simple.

Se trata de una función de envío para un lenguaje orientado a objetos. Yo preferiría que fuera rápido.

Lo que me gustaría es una manera de:

  • eliminar de la pila el primer argumento utilizado por @ 1
  • rama a la segunda función.

La segunda función sería entonces ser ejecutado en el lugar de la primera (que es una llamada de cola), pero con una lista de argumentos que no se sabe exactamente a la primera función (vararg de la primera función).

+0

¿Existe una opción para escribir dicho código en C, compilarlo con clang/llvm-gcc y desensamblar el '.bc'? – osgx

+0

Hay un desensamblador llvm: 'llvm-dis'. Lo que quiero hacer no se puede hacer en C. – Mildred

Respuesta

3

Primero: No se puede utilizar la llamada en la cola si desea pasar varargs:

http://llvm.org/docs/LangRef.html

  1. El opcional "cola" marcador indica que la función destinatario de la llamada no tiene acceso a ningún allocas o varargs en la persona que llama.

Segundo: ¿Cuál es su convenio de llamadas?

Tercero: Para manejar varargs (como en C) es necesario utilizar va_* funciones para crear un nuevo va_list y copiar todos los parámetros en él:

http://llvm.org/docs/LangRef.html#int-varargs

Última: Cada función que será llamada por este despachador debe usar las funciones va_* para obtener sus argumentos.

ACTUALIZACIÓN:

Usted debe saber qué convención de llamada va a utilizar (lo que es el valor por defecto) antes que va a decir acerca de pila como almacenamiento de argumentos de la función. Entonces. No se puede acceder sin pasar el argumento "..." sin las funciones va_ *, porque es la ÚNICA forma de acceder a ellos en el ensamblaje LLVM.

Hay una manera de hacer smth como en C, aquí el printf llamará a vfprintf con todo "..."Argumentos y sin saber cuántos argumentos para transmitir

// 3-clause BSD licensed to The Regents of the University of California. 

int 
printf(const char *fmt, ...) 
{ 
     int ret; 
     va_list ap; 

     va_start(ap, fmt); 
     ret = vfprintf(stdout, fmt, ap); 
     va_end(ap); 
     return (ret); 
} 

vfprintf se declara en forma especial para obtener" ..." y para extraer argumentos de ella:

int 
vfprintf(FILE *fp, const char *fmt0, __va_list ap) 
{ 
... 
va_arg(ap, type) //to get next arg of type `type` 
+0

Ya vi todo eso ... Modifiqué mi pregunta para explicar lo que quiero mejor – Mildred

+0

Mi convención de llamadas es la que sea la predeterminada. Y no quiero usar las funciones va_ * porque no pueden hacer lo que quiero. – Mildred

+0

osgx deberías ser más psíquico. ¡haz que la lectura mental funcione un poco mejor! –

1

(Esta crecieron demasiado grande para un comentario. Me temo que no tengo mucha experiencia práctica con LLVM, así que tome esto con un grano de sal)

He estado pensando en esto y dudo que sea capaz de escribir tal función.

Considere escribir esta función en lenguaje ensamblador x86_64 utilizando la convención de llamadas C, o realmente cualquiera que admita varargs (vea pg. 20 para un ejemplo). Normalmente cambiaría los registros (rdi < -rsi, rsi < -rdx y así sucesivamente) antes de la bifurcación, pero no debería hacer eso si los argumentos son, por ejemplo, flota, ¡entonces tienes que saber sobre los tipos! O tiene que usar una función similar a vfprintf.

Existen argumentos similares para otras arquitecturas, por lo que consideraría pensar en otra forma de resolver el problema. En particular, ¿no podría simplemente reemplazar la llamada al @1 con una búsqueda en una tabla de salto y una bifurcación en el puntero de función especificado por %identifier? Esto podría convertirse en una función que compruebe %identifier y devuelva el puntero de función correcto y maneje los identificadores inválidos de manera apropiada.

+0

Creo que tiene razón, no hay forma de hacerlo en el ensamblaje de LLVM, intentaré encontrar otra manera de hacer las cosas. Quiero que la implementación de '@ 1' permanezca opaca para la persona que llama, por lo que probablemente devuelva un puntero a la función y correspondería a la persona que llama llamarlo. Dejaré que LLVM lo incluya si cree que es mejor. – Mildred

Cuestiones relacionadas