Хорошо, обо всем по порядку, s
и d
в rsi
и rdi
означают источник и пункт назначения. Это может работать по-другому (как у вас есть), но вы расстроите многих CDO, таких как я (a) : -)
Но, для вашего фактического проблема, посмотрите здесь:
end_count:
mov [message], rsi
I предположим , который предназначен для копирования последнего байта 0x10
в место назначения, но есть две проблемы:
message
- это начало буфера, а не позиция, куда должен идти байт. - Вы копируете туда многобайтовую переменную
rsi
, а небайт, который вам нужен.
Эти два момента означают, что вы вводите какое-то странное значение в первые несколько байтов, как подсказывают ваши симптомы.
Возможно, лучший способ сделать этобыть следующим:
mov rsi, hello ; as Gordon Moore intended :-)
mov rdi, message
put_str_into_message:
mov al, byte [rsi] ; get byte, increment src ptr.
inc rsi
mov byte [rdi], al ; put byte, increment dst ptr.
inc rdi
cmp al, 10 ; continue until newline.
jne put_str_into_message
ret
Для полноты, если вы не хотели скопировать символ новой строки (хотя это в значительной степени то, что вы имеете сейчас, только с помощью tошибочный повреждающий буфер mov
убран) (б) :
put_str_into_message:
mov al, byte [rsi] ; get byte.
cmp al, 10 ; stop before newline.
je stop_str
mov byte [rdi], al ; put byte, increment pointers.
inc rsi
inc rdi
jmp put_str_into_message
stop_str:
ret
(а) CDO
является обсессивно-компульсивным расстройством, но с правильно расположенными буквами: -)
(b) Или цикл не-копирования-новой строки может быть выполнен более эффективно, при этом все еще имея одну ветвьвнизу.
Циклирование одного байта за раз все еще очень неэффективно (x86-64
имеет SSE2
, что позволяет копировать и проверять 16 байтов за раз). Поскольку у вас есть длина как константа времени сборки hello_len
, вы можете использовать ее для эффективного копирования в широких чанках (возможно, потребуется специальная обработка в конце, если размер буфера не кратен 16), или с rep movsb
.
Но это демонстрирует эффективную структуру цикла, избегая ложной зависимости слияния нового AL
в нижнюю часть RAX
, позволяя exec-of-order exec запускаться вперед и «видеть» циклвыход из ветви ранее.
strcpy_newline_end:
movzx eax, byte [rsi] ; get byte (without false dependency).
cmp al, 10
je copy_done ; first byte isn't newline, enter loop.
copy_loop: ; do:
mov [rdi], al ; put byte.
inc rsi ; increment both pointers.
inc rdi
movzx eax, byte [rsi] ; get next byte.
cmp al, 10
jne copy_loop ; until you get a newline.
; After falling out of the loop (or jumping here from the top)
; we've loaded but *not* stored the terminating newline
copy_done:
ret
Вы также должны знать, что есть другие приемы, которые вы можете использовать для сохранения инструкций внутри цикла, таких как адресация одной строки относительно другой (с помощьюиндексированный режим адресации для нагрузки, увеличивающий только один указатель).
Однако мы не будем здесь подробно останавливаться на них, так как это рискует сделать ответ более сложным, чем необходимо.