Как я могу заставить GCC компилировать секцию .text как доступную для записи в двоичном файле ELF? - PullRequest
7 голосов
/ 10 января 2012

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

Однако секция .text библиотеки, которую я использую, недоступна для записи (как в случае большинства программ).У меня есть исходный код библиотеки, и поэтому я хотел бы использовать GCC, чтобы скомпилировать его как доступный для записи.

Есть ли способ сделать это?

Ответы [ 4 ]

9 голосов
/ 10 января 2012

В общем смысле mprotect является предпочтительным выбором (в системах, соответствующих POSIX) под sys/mman.h (отметьте http://linux.die.net/man/2/mprotect).. Просто получите адрес и количество системных страниц исполняемой секции вашего процесса и вызовите mprotect для запроса разрешений; запись в него; затем снова вызовите mprotect, чтобы освободить разрешение на запись.

Однако, если это предназначено для низкоуровневых подпрограмм, где скорость имеет абсолютное значение (или mprotect недоступна), тогда вы захотите скомпилировать библиотеку с ее секцией .text, доступной для записи как вызывающую mprotect Скорее всего, возникает сбрасывание Translation Lookaside Buffer (TLB), которое (особенно в многопроцессорной среде) может и станет причиной узкого места. Если конкретная система использует аппаратную защиту с помощью подкачки (что сейчас есть почти у всех), то единственный способ изменить защиту - выполнить сброс TLB, который должен выполняться на каждой странице, на которую ссылаются, на таблицу ссылочных страниц (группу страниц), на которую ссылаются каталог страниц (группа таблиц страниц) и каждый процессор. Чтобы завершить это, это должно быть выполнено в кольце 0, который требует системного вызова, который просто помещает вишню сверху для накладных расходов.

В последнем случае самым простым решением было бы нормально скомпилировать библиотеку, а затем objcopy с помощью --writable-text (как упомянуто ggiroux).

Другое решение - определить файл карты компоновщика linker.ld самостоятельно. Тогда вы можете явно указать разрешения для любого раздела. Это не слишком сложно; если зависит от системы. См. Документацию по http://www.math.utah.edu/docs/info/ld_3.html.. Вы также можете просмотреть предоставленный системой файл linker.ld и изменить его оттуда. Передача -Wl,--verbose в gcc заставит компоновщик выложить все соответствующие файлы (включая его по умолчанию linker.ld), в котором вы можете затем изменить разрешения раздела .text и перекомпилировать библиотеку (навсегда), используя новый linker.ld файл.

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

6 голосов
/ 10 января 2012

Попробуйте objcopy --writable-text в скомпилированной библиотеке, в соответствии с документацией это должно сделать .text доступным для записи.

2 голосов
/ 21 мая 2014

Самый простой способ, который я нашел (binutils 2.22), это связать с -N, который может быть передан в gcc с помощью gcc -XN

1 голос
/ 10 января 2012

Вероятно, наилучшим подходом является использование системного API-интерфейса для изменения возможности записи памяти, которую вы хотите изменить, изменить ее, а затем вернуть обратно.

В системах семейства Unix вы захотитепосмотрите на mprotect.Просто помните, что он имеет дело с блоками, кратными размеру страницы вашей системы.Вероятно, 4096, так что округление, скорее всего, потребуется.

...