On slide 20 of the 3rd compilers handout, the x86 implementation of the FST Jargon VM instruction is shown to be:

movl 4(%esp), %edx // 4 bytes, 1 word, after header
movl %edx, (%esp) // replace “a” with “v1” at top of stack

and there is a helpful diagram too:

diagram for FST

I am now convinced that the first of these two instructions is incorrect, since it is missing a level of indirection, and instead of taking the value v1 from the heap, the value below a on the stack would be taken, as shown in the (poorly) modified diagram below.

diagram2 for FST

Since I sometimes find manuals (and generally human languages) confusing when talking about things like this, I took a more practical approach and wrote an example program that demonstrates the situation. This can be found in poc.asm. It is written in the Intel syntax, since I am more comfortable with that, however, after compilation I used objdump to acquire a dissassembly listing in both flavours, which can be seen below. This step can be easily reproduced using the att and intel targets in the attached Makefile.

Intel syntax:

8048410: 68 aa aa aa aa        push   0xaaaaaaaa
8048415: 68 9c 96 04 08        push   0x804969c
804841a: 8b 54 24 04           mov    edx,DWORD PTR [esp+0x4]
804841e: 52                    push   edx
804841f: 68 a0 96 04 08        push   0x80496a0
8048424: e8 b7 fe ff ff        call   80482e0 <printf@plt>
8048429: 83 c4 10              add    esp,0x10
804842c: b8 00 00 00 00        mov    eax,0x0
8048431: c3                    ret
8048432: 66 90                 xchg   ax,ax
8048434: 66 90                 xchg   ax,ax
8048436: 66 90                 xchg   ax,ax
8048438: 66 90                 xchg   ax,ax
804843a: 66 90                 xchg   ax,ax
804843c: 66 90                 xchg   ax,ax
804843e: 66 90                 xchg   ax,ax

GAS syntax:

8048410: 68 aa aa aa aa        push   $0xaaaaaaaa
8048415: 68 9c 96 04 08        push   $0x804969c
804841a: 8b 54 24 04           mov    0x4(%esp),%edx
804841e: 52                    push   %edx
804841f: 68 a0 96 04 08        push   $0x80496a0
8048424: e8 b7 fe ff ff        call   80482e0 <printf@plt>
8048429: 83 c4 10              add    $0x10,%esp
804842c: b8 00 00 00 00        mov    $0x0,%eax
8048431: c3                    ret
8048432: 66 90                 xchg   %ax,%ax
8048434: 66 90                 xchg   %ax,%ax
8048436: 66 90                 xchg   %ax,%ax
8048438: 66 90                 xchg   %ax,%ax
804843a: 66 90                 xchg   %ax,%ax
804843c: 66 90                 xchg   %ax,%ax
804843e: 66 90                 xchg   %ax,%ax

Note that the instruction at address 0x0804841a is exactly the disputed instruction from below. (The slides use the mnemonic movl, but objdump does not output a prefix when the operand size can be unambiguously determined from the context, as it is the case here. I did not find a truly authoritative source on this, but Wikipedia says If the suffix is not specified, and there are no memory operands for the instruction, GAS infers the operand size from the size of the destination register operand (the final operand)., and TLDP says However, gas does not require strict AT&T syntax, so the suffix is optional when size can be guessed from register operands, and else defaults to 32-bit (with a warning). , plus operand size should not matter anyway.)

This proof of concept code first pushes a dummy value (0xAAAAAAAA) on the stack, then pushes a 'heap address', where two dummy values (0xBBBBBBBB, and 0xCCCCCCCC) are stored (these correspond to the header and the first/left value of a from the example in the notes).

After assembling, and linking with the C library (make poc.x), running poc.x outputs: result is: AAAAAAAA, verifying that indeed the incorrect value is loaded, as in the second diagram above.

Debugging in GDB (with peda installed) nicely demonstrates what is happening inside the binary.

gdb-peda$ start
[----------------------------------registers-----------------------------------]
EAX: 0xf7fa7de0 --> 0xffffdd9c --> 0xffffdf41 ("COLORFGBG=15;default")
EBX: 0x0 
ECX: 0x8fd793fa 
EDX: 0xffffdd24 --> 0x0 
ESI: 0x1 
EDI: 0xf7fa6000 --> 0x1b5db0 
EBP: 0x0 
ESP: 0xffffdcfc --> 0xf7e08497 (<__libc_start_main+247>:    add    esp,0x10)
EIP: 0x8048410 (<main>: push   0xaaaaaaaa)
EFLAGS: 0x296 (carry PARITY ADJUST zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x804840b <frame_dummy+43>:  xchg   ax,ax
   0x804840d <frame_dummy+45>:  xchg   ax,ax
   0x804840f <frame_dummy+47>:  nop
=> 0x8048410 <main>:    push   0xaaaaaaaa
   0x8048415 <main+5>:  push   0x804969c
   0x804841a <main+10>: mov    edx,DWORD PTR [esp+0x4]
   0x804841e <main+14>: push   edx
   0x804841f <main+15>: push   0x80496a0
[------------------------------------stack-------------------------------------]
0000| 0xffffdcfc --> 0xf7e08497 (<__libc_start_main+247>:   add    esp,0x10)
0004| 0xffffdd00 --> 0x1 
0008| 0xffffdd04 --> 0xffffdd94 --> 0xffffdf0b ("/home/gabor/cambridge/work/1b/compilers/gas_asm/poc.x")
0012| 0xffffdd08 --> 0xffffdd9c --> 0xffffdf41 ("COLORFGBG=15;default")
0016| 0xffffdd0c --> 0x0 
0020| 0xffffdd10 --> 0x0 
0024| 0xffffdd14 --> 0x0 
0028| 0xffffdd18 --> 0xf7fa6000 --> 0x1b5db0 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value

Temporary breakpoint 1, 0x08048410 in main ()
gdb-peda$ ni
[----------------------------------registers-----------------------------------]
EAX: 0xf7fa7de0 --> 0xffffdd9c --> 0xffffdf41 ("COLORFGBG=15;default")
EBX: 0x0 
ECX: 0x8fd793fa 
EDX: 0xffffdd24 --> 0x0 
ESI: 0x1 
EDI: 0xf7fa6000 --> 0x1b5db0 
EBP: 0x0 
ESP: 0xffffdcf8 --> 0xaaaaaaaa 
EIP: 0x8048415 (<main+5>:   push   0x804969c)
EFLAGS: 0x296 (carry PARITY ADJUST zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x804840d <frame_dummy+45>:  xchg   ax,ax
   0x804840f <frame_dummy+47>:  nop
   0x8048410 <main>:    push   0xaaaaaaaa
=> 0x8048415 <main+5>:  push   0x804969c
   0x804841a <main+10>: mov    edx,DWORD PTR [esp+0x4]
   0x804841e <main+14>: push   edx
   0x804841f <main+15>: push   0x80496a0
   0x8048424 <main+20>: call   0x80482e0 <printf@plt>
[------------------------------------stack-------------------------------------]
0000| 0xffffdcf8 --> 0xaaaaaaaa 
0004| 0xffffdcfc --> 0xf7e08497 (<__libc_start_main+247>:   add    esp,0x10)
0008| 0xffffdd00 --> 0x1 
0012| 0xffffdd04 --> 0xffffdd94 --> 0xffffdf0b ("/home/gabor/cambridge/work/1b/compilers/gas_asm/poc.x")
0016| 0xffffdd08 --> 0xffffdd9c --> 0xffffdf41 ("COLORFGBG=15;default")
0020| 0xffffdd0c --> 0x0 
0024| 0xffffdd10 --> 0x0 
0028| 0xffffdd14 --> 0x0 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x08048415 in main ()
gdb-peda$ ni
[----------------------------------registers-----------------------------------]
EAX: 0xf7fa7de0 --> 0xffffdd9c --> 0xffffdf41 ("COLORFGBG=15;default")
EBX: 0x0 
ECX: 0x8fd793fa 
EDX: 0xffffdd24 --> 0x0 
ESI: 0x1 
EDI: 0xf7fa6000 --> 0x1b5db0 
EBP: 0x0 
ESP: 0xffffdcf4 --> 0x804969c --> 0xbbbbbbbb 
EIP: 0x804841a (<main+10>:  mov    edx,DWORD PTR [esp+0x4])
EFLAGS: 0x296 (carry PARITY ADJUST zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x804840f <frame_dummy+47>:  nop
   0x8048410 <main>:    push   0xaaaaaaaa
   0x8048415 <main+5>:  push   0x804969c
=> 0x804841a <main+10>: mov    edx,DWORD PTR [esp+0x4]
   0x804841e <main+14>: push   edx
   0x804841f <main+15>: push   0x80496a0
   0x8048424 <main+20>: call   0x80482e0 <printf@plt>
   0x8048429 <main+25>: add    esp,0x10
[------------------------------------stack-------------------------------------]
0000| 0xffffdcf4 --> 0x804969c --> 0xbbbbbbbb 
0004| 0xffffdcf8 --> 0xaaaaaaaa 
0008| 0xffffdcfc --> 0xf7e08497 (<__libc_start_main+247>:   add    esp,0x10)
0012| 0xffffdd00 --> 0x1 
0016| 0xffffdd04 --> 0xffffdd94 --> 0xffffdf0b ("/home/gabor/cambridge/work/1b/compilers/gas_asm/poc.x")
0020| 0xffffdd08 --> 0xffffdd9c --> 0xffffdf41 ("COLORFGBG=15;default")
0024| 0xffffdd0c --> 0x0 
0028| 0xffffdd10 --> 0x0 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x0804841a in main ()
gdb-peda$ ni
[----------------------------------registers-----------------------------------]
EAX: 0xf7fa7de0 --> 0xffffdd9c --> 0xffffdf41 ("COLORFGBG=15;default")
EBX: 0x0 
ECX: 0x8fd793fa 
EDX: 0xaaaaaaaa 
ESI: 0x1 
EDI: 0xf7fa6000 --> 0x1b5db0 
EBP: 0x0 
ESP: 0xffffdcf4 --> 0x804969c --> 0xbbbbbbbb 
EIP: 0x804841e (<main+14>:  push   edx)
EFLAGS: 0x296 (carry PARITY ADJUST zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x8048410 <main>:    push   0xaaaaaaaa
   0x8048415 <main+5>:  push   0x804969c
   0x804841a <main+10>: mov    edx,DWORD PTR [esp+0x4]
=> 0x804841e <main+14>: push   edx
   0x804841f <main+15>: push   0x80496a0
   0x8048424 <main+20>: call   0x80482e0 <printf@plt>
   0x8048429 <main+25>: add    esp,0x10
   0x804842c <main+28>: mov    eax,0x0
[------------------------------------stack-------------------------------------]
0000| 0xffffdcf4 --> 0x804969c --> 0xbbbbbbbb 
0004| 0xffffdcf8 --> 0xaaaaaaaa 
0008| 0xffffdcfc --> 0xf7e08497 (<__libc_start_main+247>:   add    esp,0x10)
0012| 0xffffdd00 --> 0x1 
0016| 0xffffdd04 --> 0xffffdd94 --> 0xffffdf0b ("/home/gabor/cambridge/work/1b/compilers/gas_asm/poc.x")
0020| 0xffffdd08 --> 0xffffdd9c --> 0xffffdf41 ("COLORFGBG=15;default")
0024| 0xffffdd0c --> 0x0 
0028| 0xffffdd10 --> 0x0 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x0804841e in main ()
gdb-peda$ ni
[----------------------------------registers-----------------------------------]
EAX: 0xf7fa7de0 --> 0xffffdd9c --> 0xffffdf41 ("COLORFGBG=15;default")
EBX: 0x0 
ECX: 0x8fd793fa 
EDX: 0xaaaaaaaa 
ESI: 0x1 
EDI: 0xf7fa6000 --> 0x1b5db0 
EBP: 0x0 
ESP: 0xffffdcf0 --> 0xaaaaaaaa 
EIP: 0x804841f (<main+15>:  push   0x80496a0)
EFLAGS: 0x296 (carry PARITY ADJUST zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x8048415 <main+5>:  push   0x804969c
   0x804841a <main+10>: mov    edx,DWORD PTR [esp+0x4]
   0x804841e <main+14>: push   edx
=> 0x804841f <main+15>: push   0x80496a0
   0x8048424 <main+20>: call   0x80482e0 <printf@plt>
   0x8048429 <main+25>: add    esp,0x10
   0x804842c <main+28>: mov    eax,0x0
   0x8048431 <main+33>: ret
[------------------------------------stack-------------------------------------]
0000| 0xffffdcf0 --> 0xaaaaaaaa 
0004| 0xffffdcf4 --> 0x804969c --> 0xbbbbbbbb 
0008| 0xffffdcf8 --> 0xaaaaaaaa 
0012| 0xffffdcfc --> 0xf7e08497 (<__libc_start_main+247>:   add    esp,0x10)
0016| 0xffffdd00 --> 0x1 
0020| 0xffffdd04 --> 0xffffdd94 --> 0xffffdf0b ("/home/gabor/cambridge/work/1b/compilers/gas_asm/poc.x")
0024| 0xffffdd08 --> 0xffffdd9c --> 0xffffdf41 ("COLORFGBG=15;default")
0028| 0xffffdd0c --> 0x0 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x0804841f in main ()
gdb-peda$ ni
[----------------------------------registers-----------------------------------]
EAX: 0xf7fa7de0 --> 0xffffdd9c --> 0xffffdf41 ("COLORFGBG=15;default")
EBX: 0x0 
ECX: 0x8fd793fa 
EDX: 0xaaaaaaaa 
ESI: 0x1 
EDI: 0xf7fa6000 --> 0x1b5db0 
EBP: 0x0 
ESP: 0xffffdcec --> 0x80496a0 ("result is: %08X\n")
EIP: 0x8048424 (<main+20>:  call   0x80482e0 <printf@plt>)
EFLAGS: 0x296 (carry PARITY ADJUST zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x804841a <main+10>: mov    edx,DWORD PTR [esp+0x4]
   0x804841e <main+14>: push   edx
   0x804841f <main+15>: push   0x80496a0
=> 0x8048424 <main+20>: call   0x80482e0 <printf@plt>
   0x8048429 <main+25>: add    esp,0x10
   0x804842c <main+28>: mov    eax,0x0
   0x8048431 <main+33>: ret    
   0x8048432 <main+34>: xchg   ax,ax
Guessed arguments:
arg[0]: 0x80496a0 ("result is: %08X\n")
arg[1]: 0xaaaaaaaa 
arg[2]: 0x804969c --> 0xbbbbbbbb 
arg[3]: 0xaaaaaaaa 
[------------------------------------stack-------------------------------------]
0000| 0xffffdcec --> 0x80496a0 ("result is: %08X\n")
0004| 0xffffdcf0 --> 0xaaaaaaaa 
0008| 0xffffdcf4 --> 0x804969c --> 0xbbbbbbbb 
0012| 0xffffdcf8 --> 0xaaaaaaaa 
0016| 0xffffdcfc --> 0xf7e08497 (<__libc_start_main+247>:   add    esp,0x10)
0020| 0xffffdd00 --> 0x1 
0024| 0xffffdd04 --> 0xffffdd94 --> 0xffffdf0b ("/home/gabor/cambridge/work/1b/compilers/gas_asm/poc.x")
0028| 0xffffdd08 --> 0xffffdd9c --> 0xffffdf41 ("COLORFGBG=15;default")
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x08048424 in main ()