Я использую MacBook Pro M1.
Я пытаюсь загрузить значение, которое я поместил в сегмент .data в своем ассемблерном коде, но когда я смотрю на значение регистра с помощью LLDB, он показывает мне 0x0.
Вот код:
.global _main
.extern print
.extern printInt
.extern exit
.align 4
.text
_main:
ldr x0, =num
b exit
.data
num: .word 5
Не беспокойтесь о ярлыке exit
, к которому я перехожу, я определил его отдельно в другом
файл сборки.
А вот регистр, считанный непосредственно перед выполнением инструкции LDR:
General Purpose Registers:
x0 = 0x0000000000000001
x1 = 0x000000016fdff2d0
А вот регистр, считанный сразу после выполнения инструкции LDR:
General Purpose Registers:
x0 = 0x0000000000000000
x1 = 0x000000016fdff2d0
Мне также очень трудно изучать ассемблер на этой машине, поэтому, если у вас есть какие-либо полезные инструменты, которые я могу использовать, было бы очень полезно, если бы вы ими поделились.
Я попытался найти, что делает инструкция LDR, но веб-сайт ARM действительно неясен и сложен для обработки, а другие инструменты бесполезны. Я понятия не имею, что происходит половину времени.
@Jester Изменение с .word
на .long
практически не повлияло на код, а добавление ldc x0, [x0]
дало мне EXC_BAD_ACCESS (code=1, address=0x0)
или, в терминах неотладчика, segmentation fault
, потому что я пытался получить доступ к 0x0.
Вы не забыли связать объектный файл с двоичным файлом? Если да, то какую команду вы для этого набрали?
@Jester: По словам Сигузы (Как загрузить данные по метке в Apple Silicon (ARM64)?), ldr x0, =num
не работает на Darwin (потому что это расширится до чего-то, что включает перемещение текста, но __TEXT
читается- только и динамический компоновщик не желает это обойти). И в ОП не упоминается запуск Linux на их MacBook. ИДК, возможно, что-то изменилось, поскольку ОП утверждает, что им удалось обойти это на шаг ldr
.
@PeterCordes По какой-то странной причине lldb не показывает мне раскрытие какой-либо инструкции, я получаю именно тот код, который написал. (Наверное, это какой-то дубляж)
@PeterCordes Также я использую MacOS
Возможно, вы выполняете отладку на уровне исходного кода. Чтобы увидеть реальные машинные инструкции, укажите LLDB, чтобы она работала в режиме дизассемблирования.
Я обязательно попробую это!
Это вина нового компоновщика Apple.
В течение долгого времени Apple использовала свой компоновщик ld64 для всех своих платформ. И в этом ответе я объясняю, почему использование ldr xN, =...
не работает в macOS и что использовать вместо этого.
Я действительно думаю, что некоторые решения, сделанные в отношении внутренней работы конвейера LLVM Mach-O (в частности, в отношении перемещения сегментов), действительно затрудняют правильную поддержку этого принципа «выдать указатель и загрузить его на ПК». -relative-label» для целей Дарвина. Но конкретный способ проявления этой ошибки зависит от выбора, сделанного компоновщиком. В идеале компоновщик должен определить, что это проблема, и выдать ошибку во время компоновки. Но ld64
, похоже, в блаженном неведении об ограничениях времени выполнения и просто выдает указатель на сегмент, где попытка перебазирования приведет к сбою процесса.
Но это было в прошлом году.
В Xcode 15 Apple объявила устаревшим ld64 и заменила его новым значением по умолчанию, которое я назвал dyld-ld
из-за отсутствия лучшего имени.
Запуск what
на этом новом ld
или вызов его с помощью -v
, используемого для идентификации его как части дерева исходного кода dyld
еще в Xcode 15.0:
PROGRAM:ld PROJECT:dyld-1015.7
Хотя, похоже, с тех пор он был выделен в отдельный проект:
PROGRAM:ld PROJECT:ld-1115.7.2
К сожалению, исходный код закрыт, поэтому мы не можем просто пойти и изучить его. Но судя по его поведению, я почти уверен, что это не форк ld64
, а переписанный с нуля.
Теперь ld64
по-прежнему поставляется как ld-classic
, и его можно выбрать в командной строке clang с помощью -ld_classic
. Если вы скомпилируете свой код с этим, а затем запустите dyld_info -fixups
на своем двоичном файле, вы увидите перезагрузку, которая должна быть применена (что приведет к сбою двоичного файла при запуске).
Если вы свяжетесь с dyld-ld
(который можно явно выбрать с помощью -ld_new
, хотя в любом случае это значение по умолчанию), то dyld_info -fixups
вообще не будет показывать перебазирование для этого указателя. А если вы исследуете его в дизассемблере, то обнаружите, что оно просто имеет значение 0
. Это означает, что такие бинарные файлы сейчас запустятся... но потом, скорее всего, просто вылетят из-за каких-то NULL
указателей. И это то, что вы видите в lldb
.
Так что да, другой симптом, та же сломанная функция. Вам все равно следует использовать adrp
+add
, как я объясняю в другом ответе.
Мне надоела эта пустота без документации в программировании на ассемблере MacOS. Откуда ты, черт возьми, все это знаешь?? Есть ли у вас какие-либо ресурсы, которыми вы могли бы поделиться?
Откуда я все это знаю? Что ж, я занимаюсь исследованиями безопасности на платформах Apple с конца 2016 года, а это просто требует глубокого погружения в суть вещей. И я де-факто сопровождаю джейлбрейк checkra1n, который по сложным причинам использует поддельный dyld во время загрузки, и первый раз я столкнулся с dyld-ld
потому, что наш поддельный dyld перестал собираться с Xcode 15, и мне пришлось это сделать. потратьте день, работая над этим. Но ресурсы по этой теме... это сложный вопрос, потому что большая часть этих знаний собирается из крошечных кусочков на протяжении многих лет.
О кодировании я знаю, потому что много лет занимаюсь взломом ядра, поэтому для этого: исходный код XNU. Что касается dyld-ld
: если у вас в какой-то момент есть свободный час, просмотрите /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/
и попытайтесь выяснить, что там делает каждый двоичный файл. Вам не нужно вникать в каждый из них, просто получите общее представление о том, что вообще включает в себя набор инструментов. Что касается ассемблерных причуд: комбинация clang -S
, исходного кода LLVM, различных баз открытого исходного кода и, что не менее важно, просто компиляции вещей и последующего просмотра их в радаре2.
Также: часть о dyld-ld
излучении NULL
вместо указателя с возможностью перебазирования я узнал сегодня, потому что Питер Кордес прокомментировал ваш пост и задался вопросом, изменилось ли что-то, поэтому я написал небольшой фрагмент сборки, скомпилировал его и увидел, что его больше нет. произошел сбой при запуске, и затем я пошел выяснять, почему. Таким образом, это меньше «знания вещей» и больше «знания того, как разобраться в чем-то на лету», что… это просто навык, который вы приобретаете со временем, когда вы получаете более полное понимание всех различных частей системы, которую вы используете. работаем с.
Прохладный! Я воспользуюсь вашим советом и постараюсь следить за обновлениями компоновщика и молюсь богу, чтобы они это исправили. Часть меня хочет просто устроиться туда на работу и исправить все это самому.
ldr x0, =num
должен загрузить адресnum
, чего, скорее всего, нет0x0000000000000001
. Таким образом, вы, вероятно, допустили какую-то ошибку во время отладки. В любом случае, вам нужно нажатьldr x0, [x0]
, чтобы загрузить значение. Кроме того,.word
является 32-битным, поэтому вы либо хотите использовать 32-битный регистр, либо.long