Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 在NASM中实现RPN计算器的堆栈_Assembly_X86_Nasm - Fatal编程技术网

Assembly 在NASM中实现RPN计算器的堆栈

Assembly 在NASM中实现RPN计算器的堆栈,assembly,x86,nasm,Assembly,X86,Nasm,我是NASM初学者,目前正在NASM中实现RPN计算器 我的第一个目标是实现一个堆栈,在这里我将保存操作数,这是我的第一次尝试:我的代码不完整,一些函数编写得不完整 section .bss STKSZ: equ 0xFF STK: resb STKSZ section .data OSP: dd STK+STKSZ ; operand stack pointer points to beginning of predefined stack of size

我是NASM初学者,目前正在NASM中实现RPN计算器

我的第一个目标是实现一个堆栈,在这里我将保存操作数,这是我的第一次尝试:我的代码不完整,一些函数编写得不完整

section .bss
STKSZ: equ 0xFF
STK: resb STKSZ

section .data
OSP: dd STK+STKSZ                   ; operand stack pointer points to beginning of predefined stack of size 255 bytes
debugMode: dd 0                     ; debug mode is set to OFF
promptMsg: db "calc: ",0

section .text
  align 16
  global main
  extern printf
  extern fprintf 
  extern fflush
  extern malloc 
  extern calloc 
  extern free 
  extern gets 
  extern getchar 
  extern fgets 

;Stack functionality: 
; _push, _pop , _isEmpty, _isFull

_push:
    push ebp                        ; function prologue
    mov ebp, esp

    push edx                        ; save registers I'm going to utilize for the sake of this         
operation

    mov edx, [ebp+8]                ; getting function's arguments to push onto our Stack impl.

    sub [OSP], 4                    ; push contents of edx onto stack 
    mov [[OSP]], edx                ; [OSP] is stack pointer, and [[OSP]] is what it actually contains? . Is this how I should do it?

    pop edx

    mov esp, ebp
    pop ebp
    ret  

myCalc:
    push ebp
    mov ebp, esp
    pushad

prompt:                             ; short piece of code to print a prompt to the user
    pushad
    push promptMsg
    call printf
    add esp, 8
    popad

read:




    jmp prompt                      ; loop around 


main:

我怀疑我的推植是正确的,有没有更好的方法?另外,如果我想使用用户定义的堆栈大小来避免几乎完全为空的堆栈,该怎么办?而不是我预先分配的最大255字节。

代码中的主要问题是mov[[OSP]],edx。不能将内存中的变量直接用作另一个变量的地址

在高级语言中,您可能主要考虑变量,而在汇编程序中,您希望尽可能多地使用寄存器。操作的每一位数据都需要首先加载到处理器中。因此,像sub[OSP],4这样看似无辜的指令实际上是cpu所关心的三条指令,其中TMP是一个内部使用的临时寄存器:

mov   TMP, [OSP]    # load the variable into a register
sub   TMP, 4        # do the actual computation
mov   [OSP], TMP    # store the result to memory
当cpu在特定地址访问内存时,它必须知道该地址,即该地址必须作为常量值或寄存器位于cpu内部。在mov[[OSP]],edx的情况下,目标地址仍然在内存中的某个地方,即在变量OSP中,而不是在cpu中,因此它无法执行该操作

您想做的是:

mov   ebx, [OSP]   # load the address to `ebx`
mov   [ebx], edx   # store the contents of edx in memory
这里,您首先将第二条指令的目标地址加载到寄存器中,以便cpu可以使用该地址

但是,由于您需要一个额外的寄存器来加载当前堆栈指针,因此最好将其与上一条指令合并,并执行以下操作:

mov   ebx, [OSP]
sub   ebx, 4
mov   [OSP], ebx
mov   [ebx], edx
最后,更好的方法是始终将操作数堆栈指针OSP保持在寄存器中。只需指定像ebx或esi这样的东西作为您的OSP,并直接使用它。对于基于堆栈的机器,无论如何,您可能一直在访问堆栈,并且几乎在任何计算中都需要该值

顺便说一句:大多数现代编程语言都遵循一种约定,即eax、ecx和edx始终可以由任何函数自由修改。如果使用两个32位值作为参数调用函数,则分别将它们放入eax和ecx中,而不是将所有内容都推送到堆栈中。如果遵循此总体方案,则不需要在函数中保存edx,因为每个函数都可以自由使用它,事实上甚至不需要堆栈帧。您可能最终拥有一个_push函数,该函数将参数推入eax,其简单程度如下:

_push:
    sub    ebx, 4
    mov    [ebx], eax
    ret
更新:关于堆栈大小:是的,您可以使用malloc,当然,只要它是黑色的,就可以拥有任何您想要的大小,也就是;-。您必须查找malloc的确切调用格式,但我假设您在eax中输入了所需的大小,并在eax中获得了一个指针。然后,如果您想将堆栈指针放入esi,例如,您可以按如下方式初始化它:

mov   eax, stack_size    ; whatever size you need
call  malloc
                         ; 'eax' is now a pointer to the new memory
mov   esi, eax           ; move the stack pointer to the end of
add   esi, stack_size    ; the new memory
...                      ; ready to go

请务必记住,如果请求1024字节,堆栈将只能容纳256个条目,因为每个条目需要4个字节。

代码中的主要问题是mov[[OSP]],edx。不能将内存中的变量直接用作另一个变量的地址

在高级语言中,您可能主要考虑变量,而在汇编程序中,您希望尽可能多地使用寄存器。操作的每一位数据都需要首先加载到处理器中。因此,像sub[OSP],4这样看似无辜的指令实际上是cpu所关心的三条指令,其中TMP是一个内部使用的临时寄存器:

mov   TMP, [OSP]    # load the variable into a register
sub   TMP, 4        # do the actual computation
mov   [OSP], TMP    # store the result to memory
当cpu在特定地址访问内存时,它必须知道该地址,即该地址必须作为常量值或寄存器位于cpu内部。在mov[[OSP]],edx的情况下,目标地址仍然在内存中的某个地方,即在变量OSP中,而不是在cpu中,因此它无法执行该操作

您想做的是:

mov   ebx, [OSP]   # load the address to `ebx`
mov   [ebx], edx   # store the contents of edx in memory
这里,您首先将第二条指令的目标地址加载到寄存器中,以便cpu可以使用该地址

但是,由于您需要一个额外的寄存器来加载当前堆栈指针,因此最好将其与上一条指令合并,并执行以下操作:

mov   ebx, [OSP]
sub   ebx, 4
mov   [OSP], ebx
mov   [ebx], edx
最后,更好的方法是始终将操作数堆栈指针OSP保持在寄存器中。只需指定像ebx或esi这样的东西作为您的OSP,并直接使用它。对于基于堆栈的机器,无论如何,您可能一直在访问堆栈,并且几乎在任何计算中都需要该值

顺便说一下:大多数现代编程语言都遵循eax、ecx和edx ar的约定 e始终可以自由地被任何函数修改。如果使用两个32位值作为参数调用函数,则分别将它们放入eax和ecx中,而不是将所有内容都推送到堆栈中。如果遵循此总体方案,则不需要在函数中保存edx,因为每个函数都可以自由使用它,事实上甚至不需要堆栈帧。您可能最终拥有一个_push函数,该函数将参数推入eax,其简单程度如下:

_push:
    sub    ebx, 4
    mov    [ebx], eax
    ret
更新:关于堆栈大小:是的,您可以使用malloc,当然,只要它是黑色的,就可以拥有任何您想要的大小,也就是;-。您必须查找malloc的确切调用格式,但我假设您在eax中输入了所需的大小,并在eax中获得了一个指针。然后,如果您想将堆栈指针放入esi,例如,您可以按如下方式初始化它:

mov   eax, stack_size    ; whatever size you need
call  malloc
                         ; 'eax' is now a pointer to the new memory
mov   esi, eax           ; move the stack pointer to the end of
add   esi, stack_size    ; the new memory
...                      ; ready to go

请务必记住,如果请求1024字节,堆栈将只能容纳256个条目,因为每个条目占用4个字节。

将函数参数放在寄存器中是一个好主意吗?在函数调用之前,让函数上的参数卡住不是很常规吗?特别是如果我想有不止一次的争论。除此之外,谢谢你的回复,我知道我做错了什么。是否有方法将堆栈的大小作为命令行参数接收?既然我想用ESI作为堆栈指针,我该如何初始化它呢?这会发生在主函数中吗?@sadElephent是的,只要可能,通常最好将函数参数放在寄存器中。如果参数是浮点值,当然不能将其放入eax中。但是eax可以作为指向实际值的指针。如果您有三个以上的参数,则可以像往常一样将其余参数放入堆栈中,尽管大多数函数需要三个或更少的参数。请注意,虽然有些体系结构中存在类似mov[[OSP]]的参数,但edx是可能的,x86不是其中之一。不过,将我的函数参数放在寄存器中是一个好主意吗?在函数调用之前,让函数上的参数卡住不是很常规吗?特别是如果我想有不止一次的争论。除此之外,谢谢你的回复,我知道我做错了什么。是否有方法将堆栈的大小作为命令行参数接收?既然我想用ESI作为堆栈指针,我该如何初始化它呢?这会发生在主函数中吗?@sadElephent是的,只要可能,通常最好将函数参数放在寄存器中。如果参数是浮点值,当然不能将其放入eax中。但是eax可以作为指向实际值的指针。如果有三个以上的参数,则可以像往常一样将其余参数放在堆栈上,尽管大多数函数需要三个或更少的参数。请注意,虽然有些体系结构中存在类似mov[[OSP]]的参数,但edx是可能的,x86不是其中之一。