programación - ¿Cómo obligo a gcc a invocar una función directamente en el código PIC?
programar pic en c mplab (2)
Considere la siguiente función:
extern void test1(void);
extern void test2(void) {
test1();
}
Este es el código que gcc genera sin -fpic
en amd64 Linux:
test2:
jmp test1
Cuando compilo con -fpic
, gcc llama explícitamente a través del PLT para habilitar la interposición de símbolos:
test2:
jmp test1@PLT
Sin embargo, esto no es estrictamente necesario para el código de posición independiente y podría omitirse si no quiero admitirlo. Si es necesario, el enlazador vuelve a escribir el objetivo de salto al símbolo PLT de todos modos.
¿Cómo puedo, sin cambiar el código fuente y sin hacer que el código compilado no sea adecuado para una biblioteca compartida, hacer que las llamadas a funciones vayan directamente a sus destinos en lugar de pasar explícitamente a través del PLT?
Si declara test1()
oculto ( __attribute__((__visibility__("hidden")))
, el salto será directo.
Ahora test1()
puede no estar definido en su unidad de traducción de origen como oculto, pero creo que no debería causar ningún daño esa discrepancia, excepto la garantía del lenguaje C de que &test1 == &test1
podría estar roto en tiempo de ejecución si se obtuvo uno de los punteros a través de una referencia oculta y una a través de una pública (la referencia pública podría haber sido interpuesta mediante precarga o un DSO anterior al actual en el ámbito de búsqueda, mientras que la referencia oculta (que da lugar a saltos directos) impide cualquier tipo de interposición)
Una forma más adecuada de tratar con esto sería definir dos nombres para test1()
un nombre público y un nombre privado / oculto.
En gcc y clang, esto se puede hacer con alias magic, que solo se puede hacer en la unidad de traducción que define el símbolo.
Las macros pueden hacerlo más bonito:
#define PRIVATE __attribute__((__visibility__("hidden")))
#define PUBLIC __attribute__((__visibility__("default")))
#define PRIVATE_ALIAS(Alias,OfWhat) /
extern __typeof(OfWhat) Alias __attribute((__alias__(#OfWhat), /
__visibility__("hidden")))
#if HERE
PUBLIC void test1(void) { }
PRIVATE_ALIAS(test1__,test1);
#else
PUBLIC void test1(void);
PRIVATE void test1__(void);
#endif
void call_test1(void) { test1(); }
void call_test1__(void) { test1__(); }
void call_ext0(void) { void ext0(void); ext0(); }
void call_ext1(void) { PRIVATE void ext1(void); ext1(); }
Lo anterior compila (-O3, x86-64) en:
call_test1:
jmp test1@PLT
call_test1__:
jmp test1__
call_ext0:
jmp ext0@PLT
call_ext1:
jmp ext1
(Definir AQUÍ = 1, además, incluye la llamada de test1, ya que es pequeña y local y -O3 está activada).
Ejemplo en vivo en https://godbolt.org/g/eZvmp7 .
-fno-semantic-interposition
también hará el trabajo, pero también rompe la garantía del lenguaje C, y es una especie de gran martillo que no tiene la granularidad del aliasing.
Si no puede cambiar el código fuente, puede usar un martillo grande: -Indicador de enlazador simbólico:
Al crear una biblioteca compartida, enlace las referencias a símbolos globales a la definición dentro de la biblioteca compartida, si corresponde. Normalmente, es posible que un programa vinculado a una biblioteca compartida anule la definición dentro de la biblioteca compartida. Esta opción solo tiene sentido en plataformas ELF que admiten bibliotecas compartidas.
Pero tenga en cuenta que se romperá si algunas partes de la biblioteca se basan en la interposición de símbolos. Recomiendo ir con funciones de ocultación que no necesitan ser exportadas (estableciendo visibilidad oculta en ellas) o llamándolas a través de alias ocultos (diseñados específicamente para hacer llamadas intra-biblioteca sin PLT de forma controlada).