Так что недавно я хотел вызвать некоторые вызовы win32 из сборки, и я использовал NASM в качестве внешнего ассемблера. Я звонил SendMessage
в своем коде следующим образом:
call __imp__SendMessageW@16
Это было собрано в относительный переход (код операции 0xE8), и результатом было нарушение доступа. В отладчике вычисленное смещение прыжка казалось правильным (в том смысле, что __imp__SendMessageW@16
действительно находилось там), но, тем не менее, оно не работало. Исследуя сборку, созданную Visual Studio, когда я вызывал функцию из C ++, я заметил, что это был не относительный немедленный переход, который он использовал, а вместо этого (на языке MASM) call dword ptr [__imp__SendMessageW@16]
, соответствующий коду операции 0xFF15. После некоторых раздумий я понял, что синтаксис NASM кодирует это как call dword near [dword __imp__SendMessageW@16]
, и после внесения изменений мой код неожиданно сработал.
Мой вопрос: почему один работает, а не другой? Происходит ли какое-то перемещение кода, которое вызывает относительный немедленный вызов где-то недружелюбно? Я никогда не был программистом на ассемблере, но у меня всегда было впечатление, что два вызова должны делать одно и то же, и главное отличие состоит в том, что один не зависит от позиции, а другой - нет (при условии, что они перемещают IP в одно и то же место ). Учитывая это, перенос теории кода имеет смысл, но тогда как объяснить, что отладчик показывает правильный адрес?
Кроме того: какова логика синтаксиса []
в этом вызове? Смещение по-прежнему является немедленным (просто с прямым порядком байтов, закодированным сразу после 0xFF15), здесь нет доступа к памяти за пределами выборки команд (я склонен думать о []
как о разыменовании вне контекста lea
). *