0

I'm trying to store a pointer in a variable located on memory. How could I dereference it? I'm trying to do it like this:

pointer: db 0 ; the pointer variable
var: db 44 ; the normal variable
dereferenced: db 0 ; the result of dereferencing the value on `pointer`
start:
  mov al, var ; move `var`'s address to `al` register
  mov [pointer], al ; storing the previously moved `var`'s address on `pointer`
  ; dereferencing should go here

PS: I'm using nasm on Linux

I've already tried [[pointer]] but it gives me an error.

PPS: The error is only when trying to dereference.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • 2
    Not in one instruction, no; x86 can't do that. You need to load it into a register. Also note that pointers are 4 or 8 bytes wide (depending on 32 vs. 64-bit mode). e.g. `mov ecx, [pointer]` / `mov [ecx], al` – Peter Cordes Aug 23 '23 at 00:01
  • Forgot to say that it's in 16-bit mode, when you boot the PC. And, the result of deferencing is actually gonna be stored on `al`. – batatinha_espacial Aug 23 '23 at 00:11
  • PS: also tried to `mov cl, [pointer]` and then `mov al, [cl]`. (and it didn't work) – batatinha_espacial Aug 23 '23 at 00:17
  • 2
    `cl` is an 8-bit register, not 16-bit which you'd need for a pointer. And 16-bit mode has extra restrictions. [Differences between general purpose registers in 8086: \[bx\] works, \[cx\] doesn't?](https://stackoverflow.com/q/53866854). And re: brackets, see [Why do you have to dereference the label of data to store something in there: Assembly 8086 FASM](https://stackoverflow.com/q/61105502) and [Referencing the contents of a memory location. (x86 addressing modes)](https://stackoverflow.com/q/34058101) – Peter Cordes Aug 23 '23 at 00:27
  • `mov al, var`. Adresses are 16-bit in real mode. Compiler doesn't protest? – Nassau Aug 23 '23 at 07:51
  • 1
    @Nassau: NASM will take the low 8 bits of the address. Usually (when making a 32-bit or 64-bit executable) this leads to a link error as the actual address doesn't fit, but when making a flat binary NASM is also the linker. And depending on the `org` setting (default 0), the absolute address may actually be small. (Since this deals with the offset part of a seg:off address.) e.g. if you assembled this source file as-is, `mov al, var` should assemble to `mov al, 1`. Using 8-bit pointers, you need to load them like `movzx bx, byte [pointer]` to zero-extend to 16-bit. – Peter Cordes Aug 23 '23 at 09:00

1 Answers1

2
pointer: db 0 ; the pointer variable

db is one byte, this means: 8 bits.

You are running a program on an x86. This means that a "normal" pointer is at least 16 bits (if you are running in 16-bit mode) in size.

I've already tried [[pointer]] but it gives me an error.

In assembly language, one instruction corresponds to one instruction that can be executed by the CPU.

In 1959, IBM built a computer that could dereference multiple levels of pointers (you would write this as [[[pointer]]]) in one single instruction. However, most modern computers are not able to do this. This is also true for x86-based computers. Such CPUs require multiple instructions to dereference a multi-level pointer:

First, they load the pointer into a register in one instruction; then they use the address in the register in the second instruction.

Example (x86, 32-bit):

mov eax, [pointer]
mov ebx, [eax]

And because one assembly instruction normally corresponds to exactly one CPU instruction, you also need to do this in assembly language.

Martin Rosenau
  • 17,897
  • 3
  • 19
  • 38
  • The most recent ISA with double-indirect addressing I know is NS32000. The famous PDP-11 has it, too. – fuz Aug 23 '23 at 09:51
  • The VAX (32-bit follow on of PDP-11) has several *deferred* addressing modes, which do a second memory access. – Erik Eidt Aug 23 '23 at 15:03
  • 1
    Since as you say it's 16-bit code, your example should be more like `mov si, [pointer]` / `mov bl, [si]`. And you mentioned `pointer: db 0` is wrong, but not what it should be instead: `pointer: dw 0`. – Nate Eldredge Aug 24 '23 at 04:10
  • @NateEldredge I wrote **at least** 16 bits (in the case of 16-bit code). However, I clarify my answer... – Martin Rosenau Aug 24 '23 at 08:32
  • 1
    Your example would be more helpful to people writing 16-bit code if loaded the pointer into `ebx`, `esi`, or `edi`, since the 16-bit versions of those register can be dereferenced. `[ax]` can't. ([Differences between general purpose registers in 8086: \[bx\] works, \[cx\] doesn't?](https://stackoverflow.com/q/53866854)). Your example would Just Work by changing both registers to 16-bit if you used EBX instead of EAX for the pointer. – Peter Cordes Aug 24 '23 at 08:44