2012-03-21 4 views
8

¿Hay alguna manera de anular las funciones con el alcance estático dentro de un módulo de objeto?¿Es posible anular las funciones estáticas en un módulo de objeto (gcc, ld, x86, objcopy)?

Si comienzo con algo como esto, un módulo con el símbolo "foo" global es una función que se llama símbolos local "barra", que llama a símbolos local "Baz"

[[email protected] ~]$ cat foo.c 
#include <stdio.h> 
static void baz(void) 
{ 
    printf("baz\n"); 
} 

static void bar(void) 
{ 
    printf("bar\n"); 
    baz(); 
} 

void foo(void) 
{ 
    printf("foo\n"); 
    bar(); 
} 

[[email protected] ~]$ gcc -g -c foo.c 
[[email protected] ~]$ objdump -x foo.o | egrep 'foo|bar|baz' 
foo.o:  file format elf32-i386 
foo.o 
00000000 l df *ABS* 00000000 foo.c 
00000000 l  F .text 00000014 baz 
00000014 l  F .text 00000019 bar 
0000002d g  F .text 00000019 foo 

Tiene uno global, "foo" y dos locales "bar" y "baz".

Supongamos que quiero escribir algunas pruebas unitarias que ejercen bar y baz, que puedo hacer:

[[email protected] ~]$ cat barbaz 
bar 
baz 
[[email protected] ~]$ objcopy --globalize-symbols=barbaz foo.o foo2.o 
[[email protected] ~]$ objdump -x foo2.o | egrep 'foo|bar|baz' 
foo2.o:  file format elf32-i386 
foo2.o 
00000000 l df *ABS* 00000000 foo.c 
00000000 g  F .text 00000014 baz 
00000014 g  F .text 00000019 bar 
0000002d g  F .text 00000019 foo 
[[email protected] ~]$ 

Y ahora bar y baz son símbolos globales y accesible desde el exterior del módulo . Hasta aquí todo bien.

Pero lo que si quiero interponer mi propia función en la parte superior de "Baz", y tienen "barra" llamar a mi interpuesta "Baz"?

¿Hay alguna manera de hacerlo?

opción --wrap no parece hacerlo ...

[[email protected] ~]$ cat ibaz.c 
#include <stdio.h> 
extern void foo(); 
extern void bar(); 

void __wrap_baz() 
{ 
    printf("wrapped baz\n"); 
} 
int main(int argc, char *argv[]) 
{ 
    foo(); 
    baz(); 
} 

[[email protected] ~]$ gcc -o ibaz ibaz.c foo2.o -Xlinker --wrap -Xlinker baz 
[[email protected] ~]$ ./ibaz 
foo 
bar 
baz 
wrapped baz 
[[email protected] ~]$ 

El Baz llamada de la principal consiguió envuelto(), pero bar todavía llama a la no Baz Baz local de la envuelta.

¿Hay alguna manera de hacer que la barra llame al baz envuelto?

Incluso si se requiere modificar el código objeto para jugar con las direcciones de las llamadas a funciones, si eso se puede hacer de manera automática, eso podría ser suficiente, pero en ese caso debe funcionar al menos en i386 y x86_64.

- Steve

+0

No he usado símbolos débiles todavía, pero suenan como baz de debilitamiento de su módulo original que le permitirán reemplazarlo por uno nuevo – x539

+0

Imagino que si trata de hacer tales cosas, no tiene acceso a la fuente código –

+0

Tengo acceso al código fuente, pero preferiría no modificar la fuente de la forma habitual de prueba unitaria. En realidad, esto es para probar un módulo de kernel de Linux. En sentido ascendente, por lo general no les gusta que pongan cambios en la fuente solo para acomodar cosas que no son kernel, y para la compatibilidad de parches, no quiero meterme con la fuente innecesariamente. – smcameron

Respuesta

3

Desde static es una promesa para el compilador de C que la función o variable es local para el archivo, el compilador es libre para eliminar ese código si se puede obtener el mismo resultado sin ella.

Esto podría estar delimitando la llamada a la función. Puede significar reemplazar una variable con constantes. Si el código está dentro de una declaración if que siempre es falsa, es posible que la función ni siquiera exista en el resultado compilado.

Todo eso significa que no puede redirigir de manera confiable las llamadas a esa función.

Si compila con las nuevas opciones -lto es aún peor, porque el compilador puede reordenar, eliminar o alinear todo el código en todo el proyecto.

+0

Me muevo por la línea mediante la compilación con -fno-en línea. No hay funciones que me interesen y que el compilador haya eliminado por completo (si no, ya las habría borrado yo mismo). Puede haber algunos casos de esquina con los que no puedo tratar, pero está bien. Estoy más interesado en el caso típico. No me opongo a la modificación mecánica del código de máquina en los sitios de llamadas para lograr este fin, solo necesito descubrir cómo hacerlo. – smcameron

1

he recibido un correo electrónico de la lanza Ian Taylor (autor de oro, un enlazador alternativa a ld):

¿Hay una manera de anular las funciones de alcance estática dentro de un módulo de objeto? (Estoy en x86_64 e i386 linux)

No, no lo hay.En particular, el compilador puede llamar en línea a las funciones estáticas , y también puede reescribir las funciones para usar una convención de llamadas diferente (GCC realiza ambas optimizaciones). Por lo tanto, no es manera confiable de anular una función estática después de que el código ha sido compilado.

La línea entrante se puede tratar con, creo, por -fno-inline, pero cambiar las convenciones de llamada es probablemente demasiado.

Dicho esto, los chicos DynamoRIO afirman ser capaces de hacerlo, pero no lo han verificado: https://groups.google.com/forum/?fromgroups#!topic/dynamorio-users/xt8JTXBCZ74

0

Si estás bien con la modificación de código de máquina, entonces debería haber ningún problema modificando el código fuente .

secuencias de comandos de escritura para producir mecánicamente las fuentes de pruebas unitarias de las fuentes reales. Perl lo hace muy bien.

Cuestiones relacionadas