Lecture 26 - x86-64

Published

April 15, 2026

Goals

  • Look at how functions work on the x86-64 architecture

x86

Before we go any further, I want to bring us back to x86 assembly. I want to get us to the point where we can use assembly as a debugging tool, so I want you to start getting familiar with the dialect that is actually used for our machine.

See the slides for an overview of the registers, addressing modes, and instructions

Let’s take a look at our last example again – this time in x86

$ gcc -c func4.c
$ objdump -Mintel -d -j .text func4.o > func4_x86.s
0000000000000000 <f>:
   0:   55                      push   rbp
   1:   48 89 e5                mov    rbp,rsp
   4:   89 7d ec                mov    DWORD PTR [rbp-0x14],edi
   7:   89 75 e8                mov    DWORD PTR [rbp-0x18],esi
   a:   89 55 e4                mov    DWORD PTR [rbp-0x1c],edx
   d:   89 4d e0                mov    DWORD PTR [rbp-0x20],ecx
  10:   44 89 45 dc             mov    DWORD PTR [rbp-0x24],r8d
  14:   44 89 4d d8             mov    DWORD PTR [rbp-0x28],r9d
  18:   8b 55 ec                mov    edx,DWORD PTR [rbp-0x14]
  1b:   8b 45 e8                mov    eax,DWORD PTR [rbp-0x18]
  1e:   01 c2                   add    edx,eax
  20:   8b 45 e4                mov    eax,DWORD PTR [rbp-0x1c]
  23:   01 c2                   add    edx,eax
  25:   8b 45 e0                mov    eax,DWORD PTR [rbp-0x20]
  28:   01 c2                   add    edx,eax
  2a:   8b 45 dc                mov    eax,DWORD PTR [rbp-0x24]
  2d:   01 c2                   add    edx,eax
  2f:   8b 45 d8                mov    eax,DWORD PTR [rbp-0x28]
  32:   01 c2                   add    edx,eax
  34:   8b 45 10                mov    eax,DWORD PTR [rbp+0x10]
  37:   01 c2                   add    edx,eax
  39:   8b 45 18                mov    eax,DWORD PTR [rbp+0x18]
  3c:   01 d0                   add    eax,edx
  3e:   89 45 fc                mov    DWORD PTR [rbp-0x4],eax
  41:   8b 45 fc                mov    eax,DWORD PTR [rbp-0x4]
  44:   5d                      pop    rbp
  45:   c3                      ret

0000000000000046 <main>:
  46:   55                      push   rbp
  47:   48 89 e5                mov    rbp,rsp
  4a:   48 83 ec 20             sub    rsp,0x20
  4e:   89 7d ec                mov    DWORD PTR [rbp-0x14],edi
  51:   48 89 75 e0             mov    QWORD PTR [rbp-0x20],rsi
  55:   6a 07                   push   0x7
  57:   6a 06                   push   0x6
  59:   41 b9 05 00 00 00       mov    r9d,0x5
  5f:   41 b8 04 00 00 00       mov    r8d,0x4
  65:   b9 03 00 00 00          mov    ecx,0x3
  6a:   ba 02 00 00 00          mov    edx,0x2
  6f:   be 01 00 00 00          mov    esi,0x1
  74:   bf 00 00 00 00          mov    edi,0x0
  79:   e8 00 00 00 00          call   7e <main+0x38>
  7e:   48 83 c4 10             add    rsp,0x10
  82:   89 45 fc                mov    DWORD PTR [rbp-0x4],eax
  85:   8b 45 fc                mov    eax,DWORD PTR [rbp-0x4]
  88:   c9                      leave
  89:   c3                      ret

We can see that it pretty much follows the same pattern as the ARM assembly did

Some differences beyond syntax and instructions:

  • there is no LR. call always pushes the return address on the stack and ret always pops it
  • for f, the compiler didn’t both updating the stack pointer
  • x86 can handle six parameters in registers before resorting to memory

Mechanical level

vocabulary

Skills