Сокрытие символов в статических библиотеках, созданных с помощью Xcode - PullRequest
44 голосов
/ 18 июля 2010

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

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

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

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

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

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

Спасибо.

Ответы [ 3 ]

49 голосов
/ 23 сентября 2013

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

  1. Устранить любые внутренние символы, необходимые между модулями, выполнив предварительную ссылку для одного объекта. Установите для параметра сборки Xcode с именем «Выполнить предварительную ссылку на один объект» значение Да (GENERATE_MASTER_OBJECT_FILE = YES). Это приводит к запуску ld с флагом "-r".
  2. Убедитесь, что для параметра "Стиль полосы" установлено значение "Неглобальные символы" (STRIP_STYLE = неглобальный), при этом "-x" передается в ld.
  3. Разбор фактически выполняется только для статических библиотек, если включена постобработка (и это не по умолчанию). Установите для параметра сборки Xcode «Постобработка развертывания» значение yes. (DEPLOYMENT_POSTPROCESSING = ДА). Также убедитесь, что для параметра «Использовать отдельную полосу» установлено значение «Да» (не всегда по умолчанию) (SEPARATE_STRIP = YES).
  4. Если, в дополнение к локальным символам, если вам необходимо удалить некоторые из глобальных символов, вы можете предоставить дополнительные параметры для команды strip в настройке сборки Xcode "Дополнительные флаги полосы". Например. Я обычно использую опцию "-R somefile", чтобы предоставить файлу дополнительный список символов, который я хочу удалить из глобальной таблицы символов.
16 голосов
/ 11 мая 2013

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

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

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

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

  3. В настройках связывания в проекте X-кода установитеТип Mach-O для «Перемещаемый объектный файл».Это означает, что все файлы .o будут перекомпонованы для создания одного объектного файла.Именно этот шаг помогает пометить все символы как частные, когда файлы .o связаны в один файл.Если вы создаете статическую библиотеку (например, файл .a), этот шаг перекомпоновки не происходит, поэтому символы никогда не скрываются.Поэтому выбор перемещаемого объектного файла в качестве цели очень важен.

  4. Даже после того, как символы помечены как частные, они все равно отображаются в файле .o.Вам нужно включить зачистку, чтобы избавиться от приватных символов.Это можно сделать, установив для параметра «Разорванный связанный продукт» значение «Да» в настройках сборки.При установке этого параметра запускается команда strip -x в объектном файле, которая удаляет частные символы из объектного файла.

  5. Дважды проверьте, что все внутренние символы пропали, запустив команду nm наокончательный перемещаемый объектный файл, сгенерированный процессом сборки.

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

1 голос
/ 04 мая 2015

Мне немного непонятно, как скрыть символы в статических библиотеках из среды командной строки 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

Что нам и нужно.

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

...