在nasm中声明一个指针

时间:2019-06-26 06:22:30

标签: assembly x86 nasm

我正在用nasm编写一个简单的os,我是汇编的新手。从c开始,我习惯于声明指针而无需为它们保留内存并随意移动它们。我该怎么做?如果我声明一个变量例如通过

var: resb 1

我知道我声明了一个指针,并且可以访问变量的值,例如由

mov eax, [var]

尽管如此,我不能将指针移动到另一个地址

mov var, 0x1234

然后我得到“操作码和操作数的无效组合”。那么如何在内存中声明和移动指针?

1 个答案:

答案 0 :(得分:2)

mov var, 0x1234会给您一个错误,因为var不是寻址模式,[var]会是,但是,您仍然会收到错误消息,因为NASM无法分辨出操作。

mov DWORD [var], 0x1234可以做到(假设您的内存模型使用32位Near指针)。

x86没有间接地址移动,而在C语言中,您可以“直接从内存中”使用指针(大致来说),在汇编中,您必须首先将指针加载到寄存器中,然后将该寄存器用作地址。
See for your self at Godbolt

int* bar;

int foo()
{
    return *bar;
}

------

foo():                                # @foo()
        mov     eax, dword ptr [bar]
        mov     eax, dword ptr [eax]
        ret
bar:
        .long   0

deference操作需要一条额外的指令,这可能看起来像是使用了两次引用,但实际上并非如此(实际上,在NASM中,人们可以将变量的名称视为指向该变量的指针,但是让事情简单点)

您可以通过简单地将指针复制到寄存器中并将其传递(上面示例中的第一个mov来做到这一点),将指针视为任何其他变量(包括对其进行复制)。
例如。

mov eax, DWORD [var]
call foo                ;Call foo with the pointer in EAX

mov DWORD [var], 0x1234 ;Change the pointer value

关于保留内存:存储在内存中的任何变量都会占用一些空间,这就是程序状态的原因。 resb用于未初始化的数据,这利用ELF功能来节省已编译二进制文件在磁盘上时的空间
如果您要制作自己的操作系统,则可能根本不使用ELF,因此resb(及类似名称)可能会因为分配零初始化的var而简单地回退(NASM会发出警告)。

如果范围有限,则可以使用堆栈临时存储您的var。这样可以通过限制内存占用空间来重复使用相同的空间。
另外,您可以使用%define来定义程序集级符号,这些符号类似于(但完全不一样)C #define s。
例如:

%define MY_PTR_TO_SOMETHING 0x1234

mov DWORD [MY_PTR_TO_SOMETHING], 1       ;In C this is *MY_PTR_TO_SOMETHING = 1;

这不会为MY_PTR_TO_SOMETHING分配空间,因为它只是数字0x1234的别名。您可以将其视为C #define MY_PTR_TO_SOMETHING ((int*)0x1234) 。或像static const int *MY_PTR_TO_SOMETHING = (int*)0x1234;那样使用编译器,它确实为指针对象本身优化了实际的静态存储。

但是请注意,由于指针值现在可以作为已知常量使用了,因此间接级别已消失。
当然,您仍然可以通过它:

mov eax, MY_PTR_TO_SOMETHING         ;EAX = Holds the value of MY_PTR_TO_SOMETHING
mov ebx, DWORD [eax]                 ;EBX = Load a DWORD from the address 0x1234
;Store or copy the EAX register to pass the pointer around

如果不习惯使用x86寻址模式,使用指针可能会造成混淆。我的建议是阅读mov的说明手册,并确保了解mov eax, 0x1234mov eax, DWORD [0x1234]之间的区别。


如果需要一个指针,可以在运行时进行修改,则需要为指针值存储一些空间;它不能是汇编时间常量或标签地址。

在C语言中,您将使用int *ptr;来为指针大小的对象在静态存储(在全局范围内)或在寄存器(或堆栈空间)中为本地范围保留空间。