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

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

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

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

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

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

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

Благодарю.

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

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

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

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

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

  2. Поскольку это библиотека, вам нужно оставить некоторые символы общедоступными. Вы должны поместить код для функций, которые хотите сохранить общедоступными в отдельных файлах, и скомпилировать эти файлы с -fvisibility=default (вы можете установить этот флаг для отдельных файлов «Build Phases> Compile Sources> – Compiler Flags» в Xcode). В качестве альтернативы вы можете префикс имени функции / classа, который вы хотите видеть, с помощью директивы __attribute__((visibility("default"))) .

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

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

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

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

Для меня немного неясно, как скрыть символы в статических библиотеках из среды командной строки 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(); } по // 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  const char *get_english_greeting(void); __attribute__((visibility("default"))) void print_greeting(void) { puts(get_english_greeting()); } по // f2.c #include  const char *get_english_greeting(void); __attribute__((visibility("default"))) void print_greeting(void) { puts(get_english_greeting()); } 

Вы хотите преобразовать эти два файла в статическую библиотеку, экспортируя как get_greeting и print_greeting но не get_english_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 

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

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

Давайте будем гением компьютера.