Limita la visibilidad de los símbolos cuando la vinculación de las bibliotecas compartidas

Algunas plataformas mandato que le proporcione una lista de una biblioteca compartida de símbolos externos para el enlazador. Sin embargo, en la mayoría de los unixish sistemas que no es necesario: todos los no-estático símbolos estará disponible de forma predeterminada.

Mi entendimiento es que el GNU toolchain, opcionalmente, puede restringir la visibilidad sólo a los símbolos declarado explícitamente. ¿Cómo puede ser logrado usando GNU ld?

InformationsquelleAutor rafl | 2009-01-12

5 Kommentare

  1. 67

    GNU ld puede hacer que en plataformas ELF.

    Aquí es como hacerlo con un enlazador versión del script:

    /* foo.c */
    int foo() { return 42; }
    int bar() { return foo() + 1; }
    int baz() { return bar() - 1; }
    
    gcc -fPIC -shared -o libfoo.so foo.c && nm -D libfoo.so | grep ' T '
    

    De forma predeterminada, todos los símbolos son exportados:

    0000000000000718 T _fini
    00000000000005b8 T _init
    00000000000006b7 T bar
    00000000000006c9 T baz
    00000000000006ac T foo
    

    Digamos que usted desea exportar sólo bar() y baz(). Crear una versión de «script» libfoo.version:

    FOO {
      global: bar; baz; # explicitly list symbols to be exported
      local: *;         # hide everything else
    };
    

    De pasar al enlazador:

    gcc -fPIC -shared -o libfoo.so foo.c -Wl,--version-script=libfoo.version
    

    Observar símbolos exportados:

    nm -D libfoo.so | grep ' T '
    00000000000005f7 T bar
    0000000000000609 T baz
    
    • no símbolos exportados sería su lugar en la lista con una minúscula t.
    • La versión de los scripts no permiten compilador para optimizar el código, así como -fvisibility=hidden.
  2. 38

    Creo que la manera más fácil de hacerlo es agregando el -fvisibility=hidden a gcc opciones y explícitamente que la visibilidad de algunos símbolos pública en el código (por __attribute__((visibility("default")))). Consulte la documentación aquí.

    Puede ser una manera de lograr que por enlazador ld secuencias de comandos, pero no sé mucho acerca de él.

    • Esto es lo que hacemos en Firefox, por ejemplo.
    • a menos que se indocumentados, debe ser: __attribute__((visibilidad(«default»))) Usted debería considerar la posibilidad de revisar su respuesta para reflejar esto. Además, el enlace está roto.
  3. 7

    El código generado para llamar a cualquier exportado funciones o el uso de cualquier exportado globals es menos eficiente que las que no exportan. Hay un nivel extra de indirección involucrados. Esto se aplica a cualquier función que podría ser exportado en compilar tiempo. gcc se sigue produciendo un extra de indirección para una función que es más tarde de la onu-exportado por un linker script. Así que, usando el atributo de visibilidad producirá un mejor código que el linker script.

  4. 1

    Si usted está usando libtool, no hay otra opción mucho como Empleado del ruso respuesta.

    Mediante su ejemplo, sería algo así como:

    cat export.sym
    bar
    baz
    

    A continuación, ejecute libtool con la siguiente opción:

    libtool -export-symbols export.sym ...
    

    Tenga en cuenta que cuando se utiliza la exportación de los símbolos de todos los símbolos NO son exportadas por defecto, y sólo a los de exportación.sym son exportados (por lo que el «local: *» la línea en libfoo.la versión es en realidad implícito en este enfoque).

    • Mismo comentario en EmployedRussian respuesta – esto genera subóptima código en comparación con -fvisibility=hidden.
  5. 0

    Parece que hay varias maneras de manejar símbolos exportados en GNU/Linux. Desde mi lectura, estos son los 3 métodos:

    • Código fuente de anotación/decoración:
      • Método 1: -fvisibility=hidden junto con __attribute__((visibility("default")))
      • Método 2 (desde GCC 4): #pragma GCC visibility
    • Método 3: Versión de secuencia de comandos (también conocido como «símbolo de mapas») pasó a la enlazador (por ejemplo. -Wl,--version-script=<version script file>)

    No voy a entrar en los ejemplos aquí, ya que son en su mayoría cubiertas por otras respuestas, pero he aquí algunas notas, pros & desventajas de los diferentes enfoques de la parte superior de mi cabeza:

    • Utilizando el anotado enfoque permite al compilador para optimizar el código un poco (uno menos direccionamiento indirecto).
    • Si se utiliza el anotado enfoque, entonces se debe considerar también el uso de strip --strip-all --discard-all.
    • Anotado enfoque puede agregar más trabajo para su función interna a nivel de pruebas de unidad desde la unidad de pruebas no puede tener acceso a los símbolos. Esto puede requerir la construcción de archivos separados: uno para el desarrollo interno & pruebas, y otro para la producción. (Este enfoque es generalmente no óptimo de una unidad de prueba purista perspectiva.)
    • Utilizando una versión del script pierde la optimización, pero permite que el símbolo de control de versiones que parece no estar disponible con el anotado enfoque.
    • Utilizando una versión de secuencia de comandos permite la unidad de pruebas suponiendo que el código es el primero construido en un archivo (.a) archivo y, a continuación, vinculado a un DSO (.así). La unidad de pruebas de enlace con el .a.

    Estoy seguro de que hay otros.

    He aquí algunas referencias (con ejemplos) que he encontrado útiles:

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein

Pruebas en línea