Подтвердить что ты не робот

Символ скрывается в статических библиотеках, построенных с помощью Xcode/gcc

Я пытаюсь выяснить, могу ли я создать статическую библиотеку, которая скрывает все свои внутренние объекты и функции и т.д., за исключением интерфейсов, которые я хочу экспортировать. Я экспериментирую с Xcode (gcc 4.2).

Я использовал атрибут __attribute__((visibility("hidden"))) для некоторых классов С++ для этой документации. Я также определил небольшие вспомогательные функции C как локальные файлы (статические) и т.д.

Однако, когда я запускаю strings в результирующем файле .a библиотеки, даже когда он скомпилирован в конфигурации Release, я все еще вижу имена моих якобы скрытых классов с именами их методов и даже именами файлов, там также располагаются локальные функции.

Я добавил -fvisibility=hidden и даже -fno-rtti в gcc-флаги. Хотя это уменьшает некоторые строки, имена классов, имена методов и имена статических функций все еще находятся в простой или искаженной форме.

Есть ли надежный способ заставить компилятор построить этот материал, не имея строковых имен всех внутренних элементов, выпущенных в двоичный файл? Не обязательно, чтобы для любых внешних клиентов были ссылки.

(Чтобы уточнить: я спрашиваю об обфускации внутренних имен, а также об обязательных требованиях к привязке экспорта. Я смущен, что все внутренние работы видны с помощью команды strings, независимо от того, формально ли эти символы экспортированы или нет.)

Спасибо.

4b9b3361

Ответ 1

Для скрытия внутренних имен требуется несколько простых настроек сборки Xcode, и обычно нет необходимости изменять источник или изменять тип встроенного продукта.

  • Устранить любые внутренние символы, необходимые между модулями, выполнив предварительную линию с одним объектом. Задайте настройку сборки Xcode с именем "Выполнить предварительную ссылку для одного объекта" на "Да" (GENERATE_MASTER_OBJECT_FILE = YES). Это заставляет ld запускаться с флагом "-r".
  • Убедитесь, что для параметра "Стиль полосы" установлено значение "Неглобальные символы" (STRIP_STYLE = неглобальный), это передает "-x" в ld.
  • Отстранение фактически выполняется только в статических библиотеках, если включена пост-обработка (и это не значение по умолчанию). Установите для параметра Xcode build "Поэтапная обработка развертывания" значение "да". (DEPLOYMENT_POSTPROCESSING = ДА). Также убедитесь, что для параметра "Использовать отдельную полосу" установлено значение "Да" (не всегда значение по умолчанию) (SEPARATE_STRIP = YES).
  • Если в дополнение к локальным символам, если вам нужно удалить некоторые глобальные символы, вы можете предоставить дополнительные параметры для команды strip, в настройке сборки Xcode "Дополнительные флаги полосы". Например. Я обычно использую опцию "-R somefile" в полосе, чтобы предоставить файл с дополнительным списком символов, который я хочу удалить из глобальной таблицы символов.

Ответ 2

Основной трюк в скрытии символов в статических библиотеках заключается в создании файла Relocatable Object (в отличие от статического библиотечного архива, который просто состоит из набора отдельных файлов .o). Чтобы создать перемещаемый объектный файл, вам нужно выбрать свою цель в XCode как Bundle (в отличие от "Cocoa Touch Static Library" ). Задача Bundle отображается под шаблонами OS X, и вы можете установить ее целевую систему в iOS в настройках сборки, если вы создаете для iOS.

Как только вы правильно настроили свою цель, следующие шаги помогут правильно скрыть символ:

  • Установите для параметра "Символы, скрытые по умолчанию" значение "Да" в настройках сборки. Это гарантирует, что все символы, скомпилированные в файлах, будут помечены как частные.

  • Поскольку это библиотека, вам нужно оставить некоторые символы общедоступными. Вы должны поместить код для функций, которые хотите сохранить общедоступными в отдельных файлах, и скомпилировать эти файлы с помощью флага -fvisibility=default (вы можете установить этот флаг для отдельных файлов "Фазы сборки" > "Скомпилировать источники" - "Компиляционные флаги" в Xcode). В качестве альтернативы вы можете префикс имени функции/класса, который вы хотите видеть, с помощью директивы __attribute__((visibility("default"))).

  • В настройках компоновки в проекте X-кода установите для типа Mach-O "Relocatable Object File". Это означает, что все файлы .o будут перенаправлены на создание одного объектного файла. Именно этот шаг помогает пометить все символы как частные, когда файлы .o связаны друг с другом в один файл. Если вы создадите статическую библиотеку (т.е. Файл .a), этот повторный шаг не произойдет, поэтому символы никогда не будут скрыты. Поэтому выбор объектного файла Relocatable в качестве целевой является критическим.

  • Даже после того, как символы были закрыты, они все еще отображаются в файле .o. Вам нужно включить удаление, чтобы избавиться от личных символов. Это можно сделать, установив для параметра "Stripped Linked Product" значение "Yes" в настройках сборки. Установка этого параметра запускает команду strip -x в объектном файле, которая удаляет личные символы из файла объекта.

  • Двойная проверка всех внутренних символов ушла, запустив команду nm в конечном перемещаемом объектном файле, сгенерированном процессом сборки.

Вышеупомянутые шаги помогут вам избавиться от имен символов из команды nm. Вы все равно увидите имена функций и имена файлов, если вы запустите команду strings в своем объектном файле (из-за того, что некоторые строки и имена объектов скомпилированы через исключения). Один из моих коллег имеет script, который переименовывает некоторые из этих символов, просматривая двоичные разделы и переименовывая эти строки. Я разместил его здесь для использования: https://gist.github.com/varungulshan/6198167. Вы можете добавить этот script в качестве дополнительного шага сборки в Xcode.

Ответ 3

Немного неясно, как скрыть символы в статических библиотеках из среды командной строки linux на основе предыдущих ответов, поэтому я просто отправлю свое решение здесь для потомков (учитывая, что это один из лучших результатов на google для этого вопроса).

Скажем, у вас есть эти два файла .c:

// f1.c
const char *get_english_greeting(void)
{
  return "hello";
}

__attribute__((visibility("default")))
const char *get_greeting(void)
{
  return get_english_greeting();
}

и

// f2.c
#include <stdio.h>
const char *get_english_greeting(void);

__attribute__((visibility("default")))
void print_greeting(void)
{
  puts(get_english_greeting());
}

Вы хотите преобразовать эти два файла в статическую библиотеку, экспортируя как get_greeting, так и print_greeting, но не get_english_greeting, которые вы не хотите статизировать, как вы хотели бы использовать ее во всей библиотеке.

Вот шаги для этого:

gcc -fvisibility=hidden -c f1.c f2.c
ld -r f1.o f2.o -o libf.o
objcopy --localize-hidden libf.o
ar rcs libf.a libf.o

Теперь это работает:

// gcc -L. main.c -lf
void get_greeting(void);
void print_greeting(void);
int main(void)
{
  get_greeting();
  print_greeting();
  return 0;
}

И это не так:

// gcc -L. main.c -lf
const char *get_english_greeting(void);
int main(void)
{
  get_english_greeting();
  return 0;
}

Для последнего вы получите эту ошибку:

/tmp/ccmfg54F.o: In function `main':
main.c:(.text+0x8): undefined reference to `get_english_greeting'
collect2: error: ld returned 1 exit status

Это то, что мы хотим.

Обратите внимание, что скрытые имена символов все еще видны в статической библиотеке, но компоновщик отказывается связываться с ними вне указанной статической библиотеки. Чтобы полностью удалить имена символов, вам необходимо снять и обфускать.