Как изменить переменную в NASM (x86, Microsoft Windows 10)

#assembly #x86 #nasm

#сборка #x86 #nasm

Вопрос:

Я хочу изменить значение переменной в NASM.

Я долго искал в интернете и много чего перепробовал.

Я уже пробовал это:

 global  _main
extern  _printf

section .data
original: db "Hello, world", 10, 0
new: db "Hello", 10, 0

section .text
_main:
    mov [original], new

    push original
    call _printf
    add esp, 4

    ret
 

Это не работает, поэтому я попробовал это сделать.

 global  _main
extern  _printf

section .data
original: db "Hello, world", 10, 0
new: db "Hello", 10, 0

section .text
_main:
    mov eax, new
    mov [original], eax

    push original
    call _printf
    add esp, 4

    ret
 

Ну, он работает без ошибок, но продолжает печатать странные вещи.

 @@
 

(На самом деле, в начале строки выше были символы в форме стрелок, указывающие вверх и вниз, но я опустил их, потому что они, похоже, не были распознаны)

Я пробовал и искал много вещей. Но я не мог найти решения. Итак, как я могу изменить значение переменной в NASM? (Я использую сборку x86 в Windows)

Спасибо.

Комментарии:

1. Это 32- или 64-битный код? Как вы собираете и связываете этот код?

2.@fuz Это то, как я скомпилировал nasm -f win32 print.asm gcc print.obj -o print.exe

3. Вы печатаете значение указателя в виде байтов ASCII, а не в указанной памяти. Просто передайте указатель на new или измените a ptr: dd original , а затем перезагрузите его.

4. вы пытаетесь изменить строку (скопировать ее сверху) или пытаетесь указать на новую строку (нажать new вместо push original)?

5. @old_timer Я собираюсь изменить значение original на значение new и нажать original. Итак, я хочу, чтобы было напечатано «Привет».

Ответ №1:

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

         mov edi, original
        mov esi, new
.loop:
        mov al, [esi]
        mov [edi], al
        add esi, 1
        add edi, 1
        test al, al
        jnz .loop
 

Комментарии:

1. Этот код предназначен для общей копии строки. В вашем примере, поскольку вы знаете длину старой и новой строк, вы можете сделать это с помощью нескольких инструкций: mov eax, [new] / mov [original], eax / mov eax, [new 4] / mov [original 4], eax . Это копирует на один байт больше, чем фактическая длина строки, что обычно безопасно, но должно выполняться только в том случае, если вы знаете , что это безопасно.

2. Регистры edi и esi должны быть сохранены вашей функцией, поэтому вы должны поместить их в начале функции и вставить в конце перед возвратом. В качестве альтернативы используйте ecx и edx в качестве указателей, которые не нужно сохранять.

3. Чтобы сделать 7-байтовую копию, вы могли бы использовать стратегию glibc memcpy / memmove из двух перекрывающихся 4-байтовых загрузок и двух хранилищ. Не имеет значения, что средний байт записывается дважды.