2012-05-03 7 views
6

Просто, чтобы дать вам некоторый контекст, вот что я пытаюсь достичь: Я вставляю const char * в общий файл объекта, чтобы иметь строку версии в самом файле .so. Я делаю анализ данных, и эта строка позволяет мне сообщить, какая версия программного обеспечения создала его. Все это прекрасно работает.Смещение в значении символа nm?

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

nm libSMPselection.so | grep _version_info 

и получить

000000000003d968 D __SMPselection_version_info 

это все хорошо, как и ожидалось (полукокс * называется _SMPselection_version_info). Однако я ожидал, что теперь вы сможете открыть файл, искать 0x3d968 и начать читать мою строку, но все, что я получаю, это мусор.

Когда я открываю файл .so и просто ищу содержимое строки (я знаю, как она начинается), я могу найти ее по адресу 0x2e0b4. По этому адресу он там, нуль завершен и как и ожидалось. (Я использую этот метод на данный момент.)

Я не компьютерный ученый. Может ли кто-нибудь объяснить мне, почему значение символа, показанное nm, неверно или по-другому, каково значение символа, если оно не является адресом символа?

(Кстати, я работаю на Mac с OSX 10.7)

ответ

2

Никто не предложил самый простой способ: Сделайте бинарный файл, который динамически загружает вашу библиотеку (дайте ей имя в командной строке) и делает dlsym() для вашего символа (или он может получить это в командной строке) для указателя строки и печатает его в stdout.

+1

Это отличная идея. Я пытаюсь это прямо сейчас. Существует только одна проблема: библиотеки, которые я тестирую, имеют довольно длинную цепочку зависимостей от других библиотек. Если я попытаюсь загрузить с помощью dlopen, то получаю ошибки, не найденные Symbol. Конечно, строка версии, которая меня интересует, не имеет зависимостей. Как заставить dl игнорировать зависимости? – Simon

+0

Я проверил. Это отлично работает, если у меня загружены все зависимости, которые являются одним из моих двух вариантов использования. Спасибо за идею. – Simon

1

В Linux у вас есть команда «строки», которые помогут вам извлечь строки из бинарных файлов.

http://linux.about.com/library/cmd/blcmdl1_strings.htm

В HPUX (и я думаю, что в других Юниксе тоже) есть подобная команда под названием «что». Он извлекает только строки, начинающиеся с «@ (#)», но если вы контролируете содержимое строки, это не проблема.

+1

Как это поможет ему получить содержимое определенного символа? – PlasmaHH

+0

«что» приятно, но я действительно хочу, чтобы моя строка была несколько строк и что останавливается на символах новой строки. Команда strings печатает всю строку, не сообщая мне, где заканчивается моя строка. Также кажется, что просто прочитал весь файл, что я и делаю. Кажется более элегантным, если я могу прочитать запись символа и сразу перейти к строке. – Simon

5

Предполагая, что это ELF или аналогично структурированный двоичный код, вы должны учитывать адрес, где загружается материал, на что влияют вещи в заголовке ELF.

Используя objdump -Fd в своем двоичном формате, вы можете иметь дизассемблер, также отображающий точное смещение файла символа.

Используя objdump -x, вы можете найти этот адрес загрузчика, обычно 0x400000 для стандартных исполняемых файлов linux.

Следующее, что вам нужно быть осторожным, - это увидеть, является ли его косвенная строка, что вы можете сделать наиболее легко, используя objdump -g. Когда строка найдена как косвенная строка, в позиции, выводимой objdump -Fd, вы не найдете строку, а адрес. Из этого вы должны снова вычесть адрес загрузчика.Позвольте мне показать вам пример одного из моих двойных звезд:

objdump -Fd BIN | grep VersionString 
    45152f:  48 8b 1d 9a df 87 00 mov 0x87df9a(%rip),%rbx  # ccf4d0 <acVersionString> (File Offset: 0x8cf4d0) 

objdump -x BIN 
... 
LOAD off 0x0000000000000000 vaddr 0x0000000000400000 paddr 0x0000000000400000 align 2**12 
... 

Таким образом, мы смотрим на 0x8cf4d0 в файле и найти в двоичный редактор:

008C:F4D0 D8 C1 89 00 00 00 00 00 01 00 00 00 FF FF FF FF 

Итак, возьмем 0x89C1D8 там, вычитать 0x400000 и есть 0x49c1d8 и когда мы смотрим там в двоичный редактор мы находим:

0049:C1D0 FF FF 7F 7F FF FF 7F FF 74 72 75 6E 6B 5F 38 30 
0049:C1E0 34 33 00 00 00 00 00 00 00 00 00 00 00 00 00 00 

Что означает «trunk_8043».

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

+0

Хорошо, спасибо, я чувствую, что ты ответил на это. То, на что я надеялся, состояло в том, чтобы получить строку без сканирования всего файла (или его дизассемблирования). Кстати, моя версия objdump не имеет опции -F (я использую GNU objdump 2.17.50.0.6-20.el5 20061020). – Simon

+0

@Simon: Это довольно древняя версия objdump (я даже не могу вспомнить, как это было в 2006 году). Вы можете получить этот файл самостоятельно, вычитая одно и то же '0x400000' смещение от' 0xccf4d0'. Возможно, есть также инструмент, который делает все это для вашего, или вы можете написать себе небольшой скрипт. – PlasmaHH

1

Почему вы ожидаете, что смещение, отображаемое nm, будет смещением в файла .so? .so файлы - это не просто образы памяти; они содержат много другой информации, а также имеют более или менее сложный формат . В Unix (по крайней мере, в большинстве Unices) общие объекты используют формат elf- . Чтобы найти информацию, вам придется интерпретировать различные поля в файле, чтобы найти нужный вам символ: , в котором сегмент и где этот сегмент начинается в файле. (Вы, вероятно, может найти библиотеку, которая упростит их чтение.)

Кроме того, если вы правы, говоря, что вы встроили char const*, то, что ваш код содержал что-то вроде:

char const* version = "..."; 

, то адрес или смещение version является адресом или смещением указателя , а не строковыми данными, на которые он указывает. Определение его как:

char const version[] = "..."; 

решит проблему.

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

+0

Сканирование всего файла - это именно то, что я делаю. Это кажется менее элегантным, и я хочу что-то узнать, поэтому задал этот вопрос. Объявление массива вместо указателя make исчезает из списка символов, отображаемых nm. – Simon

+1

@Simon Ну, это более элегантно, чтобы правильно разбирать файл, но это также намного больше. Что касается объявления массива вместо указателя, причина его исчезновения связана с тонкостью C++: объект const имеет внутреннюю привязку по умолчанию. Если вы объявите его 'extern char const version [] =" ... "', этого не произойдет; внешняя связь 'extern' и инициализация делают его определением, а не декларацией. –

+0

Спасибо, конечно, я забыл о связи! Используя ключевое слово 'extern', строка теперь появляется в таблице символов, а адрес, который я получаю от' nm', фактически соответствует местоположению укуса, теперь он работает. Я могу получить строку, обратившись к адресу, который я получаю от 'nm'! – Simon

Смежные вопросы