GNU/Linux >> Znalost Linux >  >> Linux

Odstraňování sdílených linuxových knihoven

Pokud svou soukromou část zabalíte do anonymního jmenného prostoru, pak ani std::abs ani private_function lze vidět v tabulce symbolů:

namespace{
#include<cmath>
  float private_function(float f)
  {
    return std::abs(f);
  }
}
extern "C" float public_function(float f)
{
        return private_function(f);
}

kompilace (g++ 4.3.3):

g++ -shared -o libtest.so test.cpp -s

kontrola:

# nm -DC libtest.so
         w _Jv_RegisterClasses
0000200c A __bss_start
         w __cxa_finalize
         w __gmon_start__
0000200c A _edata
00002014 A _end
000004a8 T _fini
000002f4 T _init
00000445 T public_function

Jen pro povšimnutí, že Ulrich Drepper napsal esej týkající se (všech?) aspektů psaní sdílených knihoven pro Linux/Unix, která kromě mnoha dalších témat zahrnuje kontrolu exportovaných symbolů.

To bylo velmi užitečné, protože bylo jasné, jak exportovat pouze funkce na whitelistu ze sdílené knihovny.


Vaše použití výchozího atributu viditelnosti a -fvisibility=hidden by mělo být rozšířeno o -fvisibility-inlines-hidden.

Měli byste také zapomenout na pokusy skrýt exporty stdlib, proč se podívejte na tuto chybu GCC.

Pokud máte všechny své veřejné symboly v konkrétních záhlavích, můžete je zabalit do #pragma GCC visibility push(default) a #pragma GCC visibility pop místo použití atributů. I když vytváříte knihovnu pro více platforem, podívejte se na Controlling Exported Symbols of Shared Libraries, kde najdete techniku ​​pro sjednocení vaší exportní strategie Windows DLL a Linux DSO.


Takže řešení, které nyní máme, je následující:

test.cpp

#include <cmath>
#include <vector>
#include <typeinfo>

struct private_struct
{
    float f;
};

float private_function(float f)
{
    return std::abs(f);
}

void other_private_function()
{
    std::vector<private_struct> f(1);
}

extern "C" void __attribute__ ((visibility ("default"))) public_function2()
{
    other_private_function();
}

extern "C" float __attribute__ ((visibility ("default"))) public_function1(float f)
{
    return private_function(f);
}

exports.version

LIBTEST 
{
global:
    public*;
local:
    *;
};

zkompilováno s

g++ -shared test.cpp -o libtest.so -fvisibility=hidden -fvisibility-inlines-hidden -s -Wl,--version-script=exports.version

dává

00000000 A LIBTEST
         w _Jv_RegisterClasses
         U _Unwind_Resume
         U std::__throw_bad_alloc()
         U operator delete(void*)
         U operator new(unsigned int)
         w __cxa_finalize
         w __gmon_start__
         U __gxx_personality_v0
000005db T public_function1
00000676 T public_function2

Což je docela blízko tomu, co hledáme. Existuje však několik problémů:

  • Musíme zajistit, abychom v interním kódu nepoužili předponu „exportovaný“ (v tomto jednoduchém příkladu „veřejné“, ale v našem případě zjevně něco užitečnějšího).
  • Mnoho názvů symbolů stále končí v tabulce řetězců, což se zdá být až na RTTI, -fno-rtti je v mých jednoduchých testech odstraní, ale je to spíše nukleární řešení.

Rád přijmu každé lepší řešení, se kterým kdokoli přijde!


Linux
  1. „který“ ekvivalent pro sdílené knihovny?

  2. Jak zobrazit všechny sdílené knihovny používané spustitelnými soubory v Linuxu?

  3. Chyba Linuxu při načítání sdílených knihoven:nelze otevřít soubor sdíleného objektu:Žádný takový soubor nebo adresář

  1. Jak zacházet s dynamickými a statickými knihovnami v Linuxu

  2. Jak udělat verzování sdílené knihovny v Linuxu?

  3. Jak nastavit googleTest jako sdílenou knihovnu v Linuxu

  1. Chyba při načítání sdílených knihoven libcrypto.so.1.1 – OpenSSL [Oprava]

  2. Linuxové 3D grafické knihovny?

  3. Úvod do sdílených knihoven Linuxu (Jak vytvořit sdílené knihovny)