Name |
Purpose |
address |
A number: a count of bytes to a particular
place in memory. By long tradition, printed in hexadecimal. |
pointer |
A variable that stores an address |
The register rsp points to the top of the stack--the value of
this register is the address of the data that was last pushed on
the stack. You can access this memory with [rsp], where the
array-looking brackets indicate a memory access:
push 3 ; store onto the stack mov rax, [rsp] ; read the memory at the top of the stack pop rdx ; clean up the stack ret
Note how this is different from using rsp without brackets, which
gives us the address, not the memory:
push 3 ; store onto the stack mov rax, rsp ; read the address of the top of the stack pop rdx ; clean up the stack ret
If a register
contains a value, like if rcx holds the value 3, you can ask
assembly to treat the register like a pointer with [rcx], but
unless you guessed a valid pointer, the code will crash with an
invalid memory access.
mov rcx,3 ; store a 3 in rcx
mov rax, [rcx] ; treat rcx like a pointer, copy value in memory into rax
ret
Because 3 isn't a valid pointer, this will crash.
Each additional item added to the stack is stored at the next smaller address (unlike every other array, which stores additional items at larger addresses). This means you can balance out a push by adding 8 to rsp, because 8 is the number of bytes in a 64-bit register.
push 3 ; store 3 onto the stack add rsp,8 ; move the stack pointer back (like pop) ret
foo: mov rax, [adult_swim] ; read memory at this label ret
adult_swim: dq 3 ; writes the constant 3 into a "Data Qword" (8 byte block)
If we leave off the square brackets, like this, instead of the 3,
we get the address of the 3, which happens to be 4198203 (or 0x400F3B):
foo: mov rax, adult_swim ; read the address (not what it points to!) ret
adult_swim: dq 3 ; writes the constant 3
This returns the address, which is fairly useless. We can use the address to access memory using the same [address] syntax:
foo: mov rcx, adult_swim ; copy the address into rcx
mov rax, [ rcx ] ; treat rcx like a pointer, copy the memory it points to into rax ret
adult_swim: dq 3 ; writes the constant 3
We can even use a raw numeric address with the memory access [] syntax, and extract the 3:
foo: mov rax, [4198201] ; read memory at this address written in decimal ret
adult_swim: dq 3 ; writes the constant 3But it's not a good idea to hardcode addresses like this, because changing the program's memory layout (for example, by adding new NetRun features, or even changing the length of the code) will change where the data gets stored.
In assembly language, a jump label *is* an address, so when we
say "jmp crazytown" we really mean "jmp to the address in memory
that we're calling 'crazytown'".
crazytown: ; function, identified by a jump label mov rax,3 ret foo: jmp crazytown mov rax,1234 ; never happens due to the jmp retThe above returns 3, just like you'd expect.
crazytown: ; a label we can jump to mov rax,3 ret foo: mov rdx,crazytown ; load address of crazytown into rdx jmp rdx ; jump to that address mov rax,1234 ; never happens due to the jmp ret
Function calls
work by storing the return address on the stack. It's not
recommended, but it is possible to manually pop this address, and
jump back to main directly.
mov rax,3 pop rdx ; main's return address jmp rdx ; equivalent to a ret!
I was surprised to discover this version actually benchmarks faster than a ret!
May not be suitable for all readers
The Knight said, "The name of the song is called 'Haddocks' Eyes.'"
"Oh, that's the name of the song, is it?" Alice said, trying to feel interested.
"No, you don't understand," the Knight said, looking a little vexed. "That's what the name is called. The name really is 'The Aged Aged Man.'"
"Then I ought to have said 'That's what the song is called'?" Alice corrected herself.
"No, you oughtn't: that's quite another thing! The song is called 'Ways And Means': but that's only what it's called, you know!"
"Well, what is the song, then? " said Alice, who was by this time completely bewildered.
"I was coming to that," the Knight said. "The song really is 'A-sitting On A Gate': and the tune's my own invention."
Lewis Carroll, Through
the Looking-Glass, 1871
name of song
song
is called
Haddocks' Eyes
Ways and Means
really is
The Aged Aged Man A-sitting On A Gate
int x=3;
int *ptr = &x;
The value of x really is 3
The value is called x
The address of x really is 4198304
The address of x is called ptr
There are only two hard
things in Computer Science: cache invalidation, and naming
things.