Распечатать rpath исполняемого файла в macOS

Я хочу изменить rpath исполняемого файла с помощью install_name_tool, но сейчас не могу понять, что такое rpath. install_name_tool требует, чтобы в командной строке были указаны как старый, так и новый rpath. Какую команду я могу использовать для печати rpath исполняемого файла в macOS?


person staticfloat    schedule 20.09.2012    source источник


Ответы (5)


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

Во-вторых, вы можете использовать otool для вывода списка rpath элементов изображения. Используя otool -l, вы получите следующий вывод, в самом конце которого находятся записи rpath:

Load command 34
          cmd LC_LOAD_DYLIB
      cmdsize 88
         name /System/Library/Frameworks/AppKit.framework/Versions/C/AppKit (offset 24)
   time stamp 2 Wed Dec 31 19:00:02 1969
      current version 1038.32.0
compatibility version 45.0.0

Load command 35
          cmd LC_RPATH
      cmdsize 40
         path @loader_path/../Frameworks (offset 12)

Найдите команды LC_RPATH и обратите внимание на путь под записью path.

РЕДАКТИРОВАТЬ: относительно того, что такое @loader_path: это общий и динамический способ обращения к объекту Mach-O, который хочет выполнить загрузку фреймворка.

Хотя это довольно надуманный пример, я думаю, что он должен донести суть. Допустим, у нас есть приложение MyApp.app, использующее фреймворк MyFramework.framework. Мы также скажем, что для правильной работы мне нужно, чтобы мое приложение было установлено в /Applications и нигде больше. Таким образом, структура указанного приложения и фреймворка будет следующей:

/Applications/MyApp.app/Contents/MacOS/MyApp (исполняемый файл) /Applications/MyApp.app/Contents/Frameworks/MyFramework.framework/MyFramework (Mach-O dylib)

Если бы мы запустили otool -L (обратите внимание на заглавную букву L) в исполняемом файле, это показало бы следующее относительно MyFramework:

@rpath/MyFramework.framework/Versions/A/MyFramework
/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa
/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation
/usr/lib/libobjc.A.dylib
/usr/lib/libSystem.B.dylib
....

Обратите внимание: поскольку MyFramework.framework использует имя/путь установки @rpath, нам потребуются записи пути поиска во время выполнения, которые будут заменены вместо @rpath во время выполнения. Теперь у меня может быть одна запись rpath:

/Applications/MyApp.app/Contents/Frameworks

Это будет работать, и во время выполнения две части будут объединены:

/Applications/MyApp.app/Contents/Frameworks + /MyFramework.framework/Versions/A/MyFramework ==

/Applications/MyApp.app/Contents/Frameworks/MyFramework.framework/Versions/A/MyFramework

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

@loader_path — это просто динамический способ ссылки на исполняемый файл приложения, где бы он ни находился в файловой системе. В этом конкретном случае во время выполнения он будет заполнен путем к работающему исполняемому файлу: /Applications/MyApp.app/Contents/MacOS/MyApp. Тогда мы можем сказать, что для того, чтобы найти MyFramework.framework, вы просто идете вверх по каталогу и переходите к Frameworks.

person NSGod    schedule 20.09.2012
comment
Что за @loader_path? - person nn0p; 26.11.2016
comment
@nn0p Я нашел эту статью полезной для понимания loader_path. - person Kevin Olree; 16.05.2017
comment
Я не мог видеть LC_RPATH в своем выводе otool -l, но я вижу имя установки в поле имени, которое следует за записью cmd LC_ID_DYLIB. - person Amos Joshua; 28.06.2017

Вы можете использовать otool -l myexecutable, но это выводит много ненужной информации, если вас интересует только список rpath.

Вы можете отфильтровать вывод otool -l по соответствующим записям rpath с помощью

otool -l myexecutable | grep RPATH -A2
person plasmacel    schedule 31.10.2018

Я обнаружил, что могу распечатать имя установки общей библиотеки в macOS, используя

otool -D mylib

Более того, я могу установить имя установки напрямую, без ссылки на старое имя установки, передав флаг -id в install_name_tool:

install_name_tool -id @rpath/my/path mylib
person Amos Joshua    schedule 28.06.2017

В настоящее время я пишу несколько сценариев Bash-3 для обработки DYLD, и этот отвечает на вопрос, поэтому я публикую его для справки:

#! /bin/bash

# ######################################################################### #

if [ ${#} -eq 0 ]
then
    echo "
Usage: ${0##*/} FILE...

List rpaths in FILEs
"    
    exit 0
fi

# ######################################################################### #

shopt -s extglob

# ######################################################################### #

for file in "${@}"
do
    if [ ! -r "${file}" ]
    then
        echo "${file}: no such file" 1>&2
        continue
    fi

    if ! [[ "$(/usr/bin/file "${file}")" =~ ^${file}:\ *Mach-O\ .*$ ]]
    then
        echo "${file}: is not an object file" 1>&2
        continue
    fi

    if [ ${#} -gt 1 ]
     then
         echo "${file}:"
    fi

    IFS_save="${IFS}"
    IFS=$'\n'

    _next_path_is_rpath=

    while read line
    do
        case "${line}" in
            *(\ )cmd\ LC_RPATH)
                _next_path_is_rpath=yes
                ;;
            *(\ )path\ *\ \(offset\ +([0-9])\))
                if [ -z "${_next_path_is_rpath}" ]
                then
                    continue
                fi
                line="${line#* path }"
                line="${line% (offset *}"
                if [ ${#} -gt 1 ]
                then
                    line=$'\t'"${line}"
                fi
                echo "${line}"
                _next_path_is_rpath=
                ;;
        esac
    done < <(/usr/bin/otool -l "${file}")

    IFS="${IFS_save}"
done

# ######################################################################### #

'Надеюсь, поможет ;-)

NB: Кто-нибудь знает некоторые приемы Bash-3, которые могут быть полезны для этого скрипта?

person Fravadona    schedule 17.04.2015
comment
Не специфичный для Bash-3 трюк, но я рекомендую писать комментарий вверху каждого скрипта, объясняющий, что он делает. Не идеально читать код, чтобы понять, почему инструмент существует. - person Barry Jones; 01.12.2020

Я просто использую команду otool

otool -l <my executable>

Он распечатывает поле rpath. Нет необходимости в длинных сценариях.

person rosewater    schedule 26.02.2016