mov rsi, "abcdefgh"
является mov-немедленной строкой содержимое , а не указателем на нее. Он существует как непосредственный, если вы это сделаете.
Ваш макрос должен будет переключиться на .rodata
и обратно, чтобы поместить строку в память; возможно, вы могли бы превратить его в последовательность push-немедленного в стек с макросами NASM, но это звучит сложно.
Таким образом, вы можете использовать обычный msglen equ $ - msg
, чтобы получить длину. (На самом деле используются локальные метки NASM, чтобы макрос не создавал конфликтов).
См. NASM - локальная метка макроса в качестве параметра для другого макроса , где я в основном написал этот ответ пару недель назад. Но не совсем дубликат, потому что в нем не было ошибки использования строки как непосредственного.
В любом случае, NASM не поддерживает AFAIK для переключения секций, а затем возвращается к текущей секции, как GAS .pushsection
. Поэтому мы застряли в жестком коде section .text
, если вы не хотите добавить необязательный параметр для имени раздела.
; write(1, string, sizeof(stringarray))
; switches to SECTION .text regardless of previous section
; clobbers: RDI, RSI, RDX, RCX,R11 (by syscall itself)
: output: RAX = bytes written, or -errno
%macro PRINT 1
section .rodata
;; NASM macro-local labels
%%str db %1 ; put the string in read-only memory
%%strln equ $ - %%str ; current position - string start
section .text
mov edx, %%strlen ; len
lea rsi, [rel %%str] ; buf = the string. (RIP-relative for position-independent)
mov edi, 1 ; fd = stdout
mov eax, WRITE
syscall
%endmacro
Это не пытается объединить дубликаты одной и той же строки. Многократное использование его с одним и тем же сообщением будет неэффективным. Это не имеет значения для отладки.
Я мог бы оставить ваши определения% для RDI и позволить NASM оптимизировать mov rdi, 1
(7 байт) до mov edi, 1
(5 байт). Но YASM этого не сделает, поэтому лучше сделать это явно, если вы заботитесь о том, чтобы кто-нибудь создавал ваш код с помощью YASM.
Я использовал REA-относительный LEA, потому что это самый эффективный способ поместить статический адрес в регистр в позиционно-независимом коде. В исполняемых файлах Linux, отличных от PIE, используйте mov esi, %%str
(5 байт и можете работать на любом порту, больше, чем LEA). Но в OS X базовый виртуальный адрес, где исполняемый файл отображается / загружается, всегда выше 2 ^ 32, и вам никогда не понадобится mov r64, imm64
с 64-битным абсолютным адресом.
В Linux, где номера системных вызовов представляют собой маленькие целые числа, вы можете использовать lea eax, [rdi-1 + WRITE]
для выполнения eax = SYS_write с 3-байтовой инструкцией против 5 для mov.