Accessing Memory in Assembly Language

CS 301: Assembly Language Programming Lecture, Dr. Lawlor

THE key to understanding pointers in assembly is to realize that everything in memory--code or data--is stored as a flat one-dimensional sequence of bytes:
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 just stores an address

Reading Data from Memory

There's a "pseudo instruction" named "dq" (data QWORD) that inserts an 8-byte constant into the code at that point.  You can then access memory using a funny syntax: you write the [address] with square brackets, and the CPU accesses memory at that address.  So this returns 3:
adult_swim:
	dq 3   ; writes the constant 3 into a "Data Qword" (8 byte block)

foo:
	mov rax, [adult_swim] ; read memory at this label
	ret

(Try this in NetRun now!)

If we leave off the square brackets, like this, instead of the 3, we get the address of the 3, which happens to be 4198304 (or 0x400FA0):

adult_swim:
	dq 3   ; writes the constant 3 into a "Data Qword" (64-bit block)

foo:
	mov rax, adult_swim ; read the address (not what it points to!)
	ret

(Try this in NetRun now!)

We can use this number as an address with the [] syntax, and extract the 3:

adult_swim:
	dq 3   ; writes the constant 3 into a "Data Qword" (64-bit block)

foo:
	mov rax, [4198304] ; read memory at this address written in decimal
	ret

(Try this in NetRun now!)

The following are also equivalent ways to access this memory:

	mov rax, [0x400FA0] ; read memory at this address written in hex

(Try this in NetRun now!)

	mov rdi, 4198304 ; maybe just a number?
	mov rax, [rdi] ; nope, it's an address!

(Try this in NetRun now!)

	mov rdi, 4       ; surely just a number
	add rdi, 4198300 ; maybe a weird number?
	mov rax, [rdi] ; nope, it's an address!

(Try this in NetRun now!)

	mov rdi, 32  
	imul rdi, 131197 ; 32 * 131197 = 4198304
	mov rax, [rdi] ; still works as an address!

(Try this in NetRun now!)

Address of the Top of the Stack

The register rsp points to the top of the stack--the value of this register is the address of the data on top of the stack.  You can access this memory with [rsp]:

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

(Try this in NetRun now!)

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

(Try this in NetRun now!)

Jumping to an Address

In assembly language, a jump label *is* an address, so when we say "jmp crazytown" we really mean "jmp to the address in memory 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
	ret

(Try this in NetRun now!)

The above returns 3, just like you'd expect. 

You can also copy the address for crazytown into a register, then jump to that register.  Having the address in a register would allow us to save and restore the address, choose between several jump locations, or index a jump.
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

(Try this in NetRun now!)

But the address of "crazytown" is just a number--it happens to equal 0x400E80 (for now).  We can load up a register with this number, and jump there directly.  This works exactly the same as the above, except it will break if I change any of the code above crazytown, which would change the address of crazytown.
crazytown:            ; a label we can jump to (or not!)
	mov rax,3
	ret

foo:
	mov rdx,0x400E80 ; load a number -- actually the address of crazytown
	jmp rdx          ; now go there!
	mov rax,1234 ; never happens due to the jmp
	ret

(Try this in NetRun now!)

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!

(Try this in NetRun now!)

I was surprised to discover this version actually benchmarks faster than a ret!

CAUTION: Arts & Humanities content

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



There are only two hard things in Computer Science: cache invalidation, and naming things.

Phil Karlton, Principal Curmudgeon at Netscape Corporation




The value really is 3
The address of the value is 4198304
The address of the value is called adult_swim
Dr. Lawlor, This Lecture Note, 2015