Assembly 将数据从堆栈中弹出到命名变量中?或者用MOV存储寄存器?
我在做一个程序,用户输入一个数字,程序从零到那个数字打印出来。这是我的密码:Assembly 将数据从堆栈中弹出到命名变量中?或者用MOV存储寄存器?,assembly,nasm,Assembly,Nasm,我在做一个程序,用户输入一个数字,程序从零到那个数字打印出来。这是我的密码: SECTION .DATA len EQU 32 SECTION .bss data resw len other resw len SECTION .TEXT GLOBAL _start _start: input: ; This section gets the integer from the user mov eax, 3 ; } mov ebx,
SECTION .DATA
len EQU 32
SECTION .bss
data resw len
other resw len
SECTION .TEXT
GLOBAL _start
_start:
input: ; This section gets the integer from the user
mov eax, 3 ; }
mov ebx, 1 ; }
mov ecx, data ; } System_read call
mov edx, len ; }
int 80h ; }
prelim:
mov ebp, 0
setup: ; This section sets up the registers ready for looping
push ebp
pop other ; THIS IS THE ERROR LINE!
mov esi, data
loop: ; This section loops, printing out from zero to the number given
mov eax, 4
mov ebx, 1
mov ecx, other
mov edx, len
int 80h
cmp ebp, esi
je exit
inc ebp
jmp setup
exit: ; Exits the program
mov eax, 1 ; }
mov ebx, 0 ; } System_exit call
int 80h ; }
我遇到的问题是,它给出的错误是操作码和操作数的组合无效。我尝试过将变量other
声明为一个字、双字、字节,但它仍然这样说。为什么会这样
本质上,我的问题是如何将寄存器中的值移动到内存中的值?
例如:
其中
memorydata
是在节中声明的数据。data
或类似的东西。首先,它应该是pop[other]
,而不是pop other
。在NASM中,other
只是一个地址,而[other]
表示该地址的内容/数据。这就是NASM与TASM和MASM的不同之处pop other
要求NASM生成一条指令,将堆栈中的数据弹出到。。。常数没有这样的指示,这样做没有任何意义。您想将内容弹出到寄存器或内存中
其次,与TASM和MASM(同样)不同,NASM不为标签名指定任何类型或大小。标签只是代码或数据中的命名位置(地址)
由于这个原因,pop[other]
对NASM来说是不明确的,因为pop
可以弹出一个单词或两个单词,而您没有指定您想要哪一个,并且NASM无法猜测适合您的大小
你应该写的是
pop word [other]
或
我强烈建议不要推送或弹出16位寄存器、变量或常量。它们使堆栈错位,这可能会导致性能降低,并由于注意力丢失而导致愚蠢的错误(例如,您推送一个32位的值,然后错误地将其弹出为16位或其他方式)。您需要弹出到一个临时寄存器,然后移动到内存目标:
POP EAX
MOV myVar,EAX
或者,您需要使用一些显式语法弹出:
POP WORD PTR[<word_sized_var>]
POP WORD PTR[]
至于将a移到内存中,有几种语法方法:
MOV <var name>,<value>
MOV [<var name>],<value>
MOV,
MOV[],
在您的例子中,您可能需要第一个:
MOV other,EBP
NASM使用与TASM和MASM不同的语法。NASM没有一些大小的PTR
。NASM不能执行MOV myVar,EAX
,因为myVar
是一个常数,它是变量的地址,而不是变量。我可以执行MOV[other],EAX
?@RileyH-Yep,这就是你应该对NASM执行的操作。@AlexeyFrunze,没错!你会想进入这个地址的!我假设在机器级别,pop
的操作码使用一个数字操作数——目标。如果将该地址的解引用值(例如,字符“a”)传递给pop指令,那就没有任何意义了,不是吗?彼得·科德斯我当时感到困惑的原因是,我过去认为汇编程序是一个很好的查找和替换工具,它会看到标记pop
并替换为,比如说,55。它将看到令牌bx
,并替换为0x02
。现在我知道用二进制表示汇编操作要复杂得多。操作码由表示操作数是哪种数据的标志组成。这最终使我能够将NASM视为一种语言,在它如何表示间接地址的背后有着自己的哲学。不管怎样,谢谢你。那没有道理。标签other
只是一个表示内存中某个位置的数字,对吗?例如,如果您已将值5存储在other
所指的地址,那么我希望pop[other]
将转换为pop 5
@JamesM。请注意,您在最后一句话中所说的没有意义。试着想象一下,想想你为什么会这样做。@JamesM.Lay:在NASM语法中,内存操作数总是需要[]
围绕地址。因此,pop[other]
是使用other
作为寻址模式,对内存目标的弹出。x86没有任何双地址寻址模式,它可以从内存中加载指针并对其进行引用。@ AlxyFrunZEZ给某人学习NASM,当你被教导将括号等同于解引用操作符时,它是完全有意义的。我的心理模型是一个函数pop:void-pop(void*address)
,和pop-other
相当于pop(other)
vspop[other]
相当于pop(*other)
。他们没有告诉你的秘密是,机器操作员比汇编助记符多。汇编程序生成的操作根据操作数的寻址模式而变化。mov符号、eax
也不汇编。我不知道关于标记行上的segfault的编辑想要说什么。
POP WORD PTR[<word_sized_var>]
MOV <var name>,<value>
MOV [<var name>],<value>