Skip to content

Instantly share code, notes, and snippets.

@dannas
Last active March 31, 2020 06:58
Show Gist options
  • Select an option

  • Save dannas/dc147b230a9ee8af8b9a969ef21e85c7 to your computer and use it in GitHub Desktop.

Select an option

Save dannas/dc147b230a9ee8af8b9a969ef21e85c7 to your computer and use it in GitHub Desktop.
Program for experimenting with C code generation of x86-64 mov instructions.
#include <stdint.h>
// Program for experimenting with C code generation of x86-64 mov instructions.
// https://godbolt.org/z/7UPcax
//
// The x86-64 has grown from the original x86 16-bit arch. A word in Intel terminology is still 16-bits (2 bytes).
// A list of instruction size suffixes
// b Byte
// w Word
// l Double-Word
// q Quad-Word
//
// The original x86 arch had eight registers (ax, bx, cx, dx, di, si, sp, bp). They are named on this form.
// al Byte
// ax Word
// eax Double-Word
// rax Quad-Word
//
// The x86-64 arch added eight registers r8-r15
// r8b Byte
// r8w Word
// r8d Double-Word
// r8 Quad-Word
//
// There are three categories of mov instructions. (X is size of src, Y is size of dest)
// movX src, dest ; dest = src
// movzXY src,dest ; dest = ZeroExtend(src).
// movsXY src,dest ; dest = SignExtend(src).
//
// The operands of a mov, movz, movs instruction can be any of these pairs (more than these exists).
// reg-reg
// reg-mem
// mem-reg
// imm-reg
// imm-mem
//
// Some quirks:
// * movb and movw moves a reg to the lower part of the dest, but leaves the upper bits untouched.
// But movl zeroes out the upper bits. Due to this, no movzlq instruction exists - movl is unsed instead.
// * movq imm, reg only moves 4 bytes and sign extends the upper 4 bytes. For moving an 8 imm, movabsq is
// needed.
// Aliases for increased readability
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef int8_t i8;
typedef int16_t i16;
typedef int32_t i32;
typedef int64_t i64;
// Generates a reg-reg mov instruction.
#define RR(Src, Dest) Dest reg_ ## Src ## _to_ ## Dest(Src val) { return val;}
// Generates a imm-reg mov instruction.
#define IR(Src, Dest) Dest imm_ ## Src ## _to_ ## Dest(void) { return (Src)0x1122334455667788L; }
// Generates a mem-reg, then reg-mem instruction pair.
#define MM(Src, Dest) void mem_ ## Src ## _to_ ## Dest(Dest *dst, Src *src) {*dst = (Dest)*src; }
// Widening unsigned reg-reg conversions
RR(u8, u16)
RR(u8, u32)
RR(u8, u64)
RR(u16, u32)
RR(u16, u64)
RR(u32, u64)
// Wideninig signed reg-reg conversions
RR(i8, i16)
RR(i8, i32)
RR(i8, i64)
RR(i16, i32)
RR(i16, i64)
RR(i32, i64)
// Unsigned imm-reg conversions
IR(u8, u8)
IR(u8, u16)
IR(u8, u32)
IR(u8, u64)
IR(u16, u16)
IR(u16, u32)
IR(u16, u64)
IR(u32, u32)
IR(u32, u64)
IR(u64, u64)
// Signed imm-reg conversions
IR(i8, i8)
IR(i8, i16)
IR(i8, i32)
IR(i8, i64)
IR(i16, i16)
IR(i16, i32)
IR(i16, i64)
IR(i32, i32)
IR(i32, i64)
IR(i64, i64)
// Widenining unsigned mem-mem conversions
MM(u8, u16)
MM(u8, u32)
MM(u8, u64)
MM(u16, u32)
MM(u16, u64)
MM(u32, u64)
// Widenining unsigned-signed mem-mem conversions
MM(u8, i16)
MM(u8, i32)
MM(u8, i64)
MM(u16, i32)
MM(u16, i64)
MM(u32, i64)
// Widenining signed mem-mem conversions
MM(i8, i16)
MM(i8, i32)
MM(i8, i64)
MM(i16, i32)
MM(i16, i64)
MM(i32, i64)
// Widenining signed-unsigned mem-mem conversions
MM(i8, u16)
MM(i8, u32)
MM(i8, u64)
MM(i16, u32)
MM(i16, u64)
MM(i32, u64)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment