NASM: переход из памяти в память через регистры - PullRequest
2 голосов
/ 27 октября 2019

У меня трудности с переносом данных из памяти в другую память в bss. Тем не менее, моя реализация работает, когда в первых двух байтах появляются странные символы, и половина моей строки также отсутствует, а другая половина в порядке.

Это значение, которое я получаю при распечатке message == �F@elcome to the new life

Мне нужна вся помощь, чего мне не хватает? Я просмотрел свой код сто раз.

    section .data
hello:       db  "Hello, Welcome to the new life! Lets begin the journey.",10
hello_len:   equ  $ - hello

    section .bss
message: resb 255

    section .text

mov rdi, hello
mov rsi, message

msg_into_message:
    cmp byte [rdi], 10          ; hello ends with a new line char
    je end_count
    mov al, byte [rdi]
    mov byte [rsi], al
    inc rsi
    inc rdi
    jmp msg_into_message

end_count:
    mov [message], rsi
    ret

    ; Prints message
    mov rsi, message
    mov rdx, hello_len
    call pre_print
    syscall

1 Ответ

5 голосов
/ 27 октября 2019

Хорошо, обо всем по порядку, s и d в rsi и rdi означают источник и пункт назначения. Это может работать по-другому (как у вас есть), но вы расстроите многих CDO, таких как я (a) : -)

Но, для вашего фактического проблема, посмотрите здесь:

end_count:
    mov [message], rsi

I предположим , который предназначен для копирования последнего байта 0x10 в место назначения, но есть две проблемы:

  1. message - это начало буфера, а не позиция, куда должен идти байт.
  2. Вы копируете туда многобайтовую переменную 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

Вы также должны знать, что есть другие приемы, которые вы можете использовать для сохранения инструкций внутри цикла, таких как адресация одной строки относительно другой (с помощьюиндексированный режим адресации для нагрузки, увеличивающий только один указатель).

Однако мы не будем здесь подробно останавливаться на них, так как это рискует сделать ответ более сложным, чем необходимо.

...