rex.W gs ins
является привилегированной инструкцией и ошибками в пространстве пользователя. Это первая инструкция вашей программы, начиная с расширения %%str db %1, 0
в вашем макросе без изменения разделов.
Не помещайте данные там, где они будут выполняться как инструкции; используйте section .rodata
для данных только для чтения.
GAS позволил бы вам сделать .pushsection .rodata
/ .popsection
для правильного расширения макроса внутри любого раздела, но для NASM я не уверен, что мы сможем сделать лучше, чем безоговорочно, переключиться на section .text
после данных.
Препроцессор NASM имеет %push [optional context-name]
/ %pop
для сохранения / восстановления контекста препроцессора, например, для вложенного повторения до препроцессора. Но это только для препроцессора, и не включает в себя восстановление старого section
.
%macro PRINT 1
...
section .rodata
%%str db %1, 0 ; arg0 + null terminator
%%strln equ $ - %%str ; current position - string start
section .text
... rest of the macro
Таким образом, после использования макроса вы безоговорочно находитесь в разделе .text
, а не в .text.cold
или любом другом пользовательском разделе.
Также обратите внимание, что директивам equ
не важно, в каком разделе они находятся (если они не используют $
в своем определении). Так что strln
должен находиться в том же разделе, что и str
, но SYS_EXIT
не имеет ничего общего с section .data
. Это константа времени сборки, которая превращается в мгновенную при использовании.
mov r64, imm64
- это неэффективный способ поместить абсолютный адрес в регистр. Требуется исправление времени загрузки в исполняемом файле PIE, и оно длиннее, чем независимое от позиции lea rsi, [rel %%str]
. NASM собирает mov rsi, str
в 10-байтовый mov r64, imm64
, тогда как YASM использует mov r/m64, sign_extended_imm32
(который даже не работает в исполняемом файле PIE). https://nasm.us/doc/nasmdo11.html#section-11.2
Возможно, вы могли бы написать макрос, который использует %ifidn
идентичное строковому условию для проверки rsi
в качестве строкового аргумента, и в этом случае ничего не делать (указатель уже находится в RSI), в противном случае используйте lea rsi, [rel %%str]
. Это не будет работать для указателя в памяти, где mov rsi, [rbx]
работало бы, хотя. Зависит от того, насколько вы хотите, чтобы ваш макрос был. Вы можете %if
условие, которое ищет [
в строке аргумента и использовать mov
вместо lea
.
Если вы хотите сохранить / восстановить все регистры, которые вы закрываете, помните, что syscall
сам блокирует RCX (сохраненный RIP) и R11 (сохраненный RFLAGS).
Обычно вы просто документируете, что регистрирует макро-клобберы; это все регистры с замкнутым вызовом в x86-64 System V. Но если вы хотите макрос отладочной печати, вы, вероятно, хотите, чтобы он все сохранял / восстанавливал? За исключением push
/ pop
уничтожить красную зону под RSP. Я не думаю, что когда-либо использовал отладочные отпечатки в asm, просто установил точки останова с помощью отладчика и нажал «продолжить», чтобы увидеть, какая точка останова будет следующей. Или просто пошаговое и наблюдаемое изменение значений регистра, например с GDB layout reg
.