2016-08-15 4 views
1

Я пытаюсь вызвать функцию - которая должна иметь абсолютный адрес при компиляции и привязке - от машинного кода. Я создаю указатель на нужную функцию и пытаюсь передать это команде вызова, но я заметил, что команда вызова занимает не более 16 или 32-разрядного адреса. Есть ли способ назвать абсолютный 64-разрядный адрес?Как выполнить инструкцию вызова с 64-битным абсолютным адресом?

Я развертываю архитектуру x86-64 и использую NASM для генерации машинного кода.

Я мог бы работать с 32-разрядным адресом, если бы мне было гарантировано, что исполняемый файл наверняка будет отображен на нижнюю 4 ГБ памяти, но я не уверен, где я мог бы найти эту информацию.

Редактировать: Я не могу использовать инструкцию callf, поскольку для этого требуется, чтобы я отключил 64-битный режим.

Second Редактировать: Я также не хочу хранить адрес в регистре и вызывать регистр, так как это критически важно для производительности, и я не могу получить служебные и служебные результаты непрямого вызова функции.

Final Редактировать: Я смог использовать инструкцию для вызова rel32, гарантируя, что мой машинный код сопоставлялся с первой 2 ГБ памяти. Это было достигнуто за счет ттар с флагом MAP_32BIT (я использую Linux):

MAP_32BIT (с Linux 2.4.20, 2.6) Поместить отображение в первые 2 Гбайта адресного пространства процесса. Этот флаг поддерживается только на x86-64, для 64-разрядных программ. Он был добавлен в , чтобы потоки стеков были размещены где-то в первых 2 ГБ памяти, чтобы улучшить контекст - производительность коммутатора на некоторых ранних 64-разрядных процессорах. Современные процессоры x86-64 больше не имеют этой проблемы, поскольку использование этого флага не является , требуемым для этих систем. Флаг MAP_32BIT равен , игнорируется при установке MAP_FIXED.

+0

Поместите его в 64-разрядный регистр и позвоните этому? Должно быть легко проверено. –

+2

Почему этот помеченный C++? – Brian

+1

Вероятно, он называет его ассемблер из C++, используя указатель на функции C++, но это действительно не имеет отношения к этому вопросу о ассемблере x86-64. –

ответ

2

TL: DR: Чтобы вызвать функцию по имени, просто используйте call func, как обычный человек, и пусть ассемблер + компоновщик позаботится об этом. Поскольку вы говорите, что используете NASM, я думаю, вы на самом деле генерируете машинный код с помощью ассемблера. Это звучало как более сложный вопрос, но я думаю, вы просто пытались спросить, безопасен ли нормальный путь.


Indirect call r/m64 (FF /2) занимает 64-битовый регистр или операнд памяти в 64-битном режиме.

Так что вы можете сделать

mov rax, func   ; mov r64, imm64 
call rax 

Или , если вы знаете, что адрес, который ваш машинный код будет храниться в, вы можете использовать обычный прямой call rel32 кодирование, после того, как вы вычислите разницу в адрес от цели до конца инструкции call.

Если вы не хотите использовать косвенный вызов, то ваша кодировка rel32 является вашим единственным вариантом.Убедитесь, что ваш машинный код переходит в низкий 2GiB, поэтому он может достигать любого адреса в низком 4GiB.


, если я мог бы быть гарантировано, что исполняемый файл будет точно отображается в нижней части 4 Гб оперативной памяти

Да, это модель код по умолчанию для Linux, Windows и OS X Инструкции AMD64 для вызова/перехода и RIP-относительная адресация используют только кодировки rel32, поэтому для всех систем по умолчанию используется «маленькая» модель кода, где код и статические данные находятся в низком 2GiB, поэтому гарантируется, что компоновщик может просто заполнить rel32 для достижения до 2G вперед или 2G назад.

x86-64 System V ABI обсуждает большие/большие модели кода, но IDK, если кто-либо когда-либо использует это, из-за неэффективности адресации данных и совершения вызовов.


Re: Эффективность: да, mov/call rax менее эффективен. Я думаю, что это значительно медленнее, если предсказание ветвления промахивается и не может обеспечить целевое предсказание от BTB. Однако даже call rel32 и jmp rel32 по-прежнему нуждаются в BTB для полной производительности. См. Slow jmp-instruction для экспериментальных результатов относительно относительного jmp next_insn, замедляющегося, когда в гигантской петле слишком много.

С помощью предикторов с горячей веткой косвенная версия - это только дополнительный размер кода и дополнительный uop (mov). Он может потреблять больше ресурсов прогнозирования, но, возможно, даже не это.

См. Также What branch misprediction does the Branch Target Buffer detect?

+0

Благодарим за полезную информацию о модели кода по умолчанию. У вас есть источник, на который я мог бы смотреть? –

+1

@ Александр Болинский: Да, этот URL-адрес в последнем абзаце моего ответа является ссылкой на официальный стандарт ABI. См. Также [x86 tag wiki] (http://stackoverflow.com/tags/x86/info) для ссылок на другие ABI. –

+0

@PeterCordes: В чем разница в производительности между 'call rel32' и' call r64'? –