From 0bf299d007ebccdacc76774248ce844dbb41415a Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Fri, 7 Mar 2025 11:39:13 +0100 Subject: [PATCH] Implemented position independent addresses for x86 --- src/asmc/move.go | 28 ++++++++++++++------------ src/x86/LoadAddress.go | 13 ++++++++++++ src/x86/LoadAddress_test.go | 40 +++++++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 13 deletions(-) create mode 100644 src/x86/LoadAddress.go create mode 100644 src/x86/LoadAddress_test.go diff --git a/src/asmc/move.go b/src/asmc/move.go index 056872c..c4f60d7 100644 --- a/src/asmc/move.go +++ b/src/asmc/move.go @@ -4,7 +4,6 @@ import ( "strings" "git.urbach.dev/cli/q/src/asm" - "git.urbach.dev/cli/q/src/config" "git.urbach.dev/cli/q/src/x86" ) @@ -17,40 +16,43 @@ func (c *compiler) move(x asm.Instruction) { c.code = x86.MoveRegisterRegister(c.code, operands.Destination, operands.Source) case *asm.RegisterLabel: - start := len(c.code) - c.code = x86.MoveRegisterNumber(c.code, operands.Register, 0x00_00_00_00) - size := 4 - opSize := len(c.code) - size - start - regLabel := x.Data.(*asm.RegisterLabel) + start := Address(len(c.code)) + c.code = x86.LoadAddress(c.code, operands.Register, 0x00_00_00_00) + end := Address(len(c.code)) + size := uint32(4) + position := end - size + opSize := position - start - if strings.HasPrefix(regLabel.Label, "data ") { + if strings.HasPrefix(operands.Label, "data ") { c.dataPointers = append(c.dataPointers, &pointer{ - Position: Address(len(c.code) - size), + Position: position, OpSize: uint8(opSize), Size: uint8(size), Resolve: func() Address { - destination, exists := c.dataLabels[regLabel.Label] + destination, exists := c.dataLabels[operands.Label] if !exists { panic("unknown label") } - return config.BaseAddress + c.dataStart + destination + 8 + destination += c.dataStart - c.codeStart + distance := destination - end + return distance + 8 }, }) } else { c.codePointers = append(c.codePointers, &pointer{ - Position: Address(len(c.code) - size), + Position: position, OpSize: uint8(opSize), Size: uint8(size), Resolve: func() Address { - destination, exists := c.codeLabels[regLabel.Label] + destination, exists := c.codeLabels[operands.Label] if !exists { panic("unknown label") } - return config.BaseAddress + c.codeStart + destination + return destination - end }, }) } diff --git a/src/x86/LoadAddress.go b/src/x86/LoadAddress.go new file mode 100644 index 0000000..fd58889 --- /dev/null +++ b/src/x86/LoadAddress.go @@ -0,0 +1,13 @@ +package x86 + +import ( + "encoding/binary" + + "git.urbach.dev/cli/q/src/cpu" +) + +// LoadAddress calculates the address with the RIP-relative offset and writes the result to the destination register. +func LoadAddress(code []byte, destination cpu.Register, offset int) []byte { + code = encode(code, AddressMemory, destination, 0b101, 8, 0x8D) + return binary.LittleEndian.AppendUint32(code, uint32(offset)) +} diff --git a/src/x86/LoadAddress_test.go b/src/x86/LoadAddress_test.go new file mode 100644 index 0000000..cedf23f --- /dev/null +++ b/src/x86/LoadAddress_test.go @@ -0,0 +1,40 @@ +package x86_test + +import ( + "testing" + + "git.urbach.dev/cli/q/src/cpu" + "git.urbach.dev/cli/q/src/x86" + "git.urbach.dev/go/assert" +) + +func TestLoadAddress(t *testing.T) { + usagePatterns := []struct { + Destination cpu.Register + Offset int + Code []byte + }{ + {x86.RAX, 0, []byte{0x48, 0x8D, 0x05, 0x00, 0x00, 0x00, 0x00}}, + {x86.RCX, 0, []byte{0x48, 0x8D, 0x0D, 0x00, 0x00, 0x00, 0x00}}, + {x86.RDX, 0, []byte{0x48, 0x8D, 0x15, 0x00, 0x00, 0x00, 0x00}}, + {x86.RBX, 0, []byte{0x48, 0x8D, 0x1D, 0x00, 0x00, 0x00, 0x00}}, + {x86.RSP, 0, []byte{0x48, 0x8D, 0x25, 0x00, 0x00, 0x00, 0x00}}, + {x86.RBP, 0, []byte{0x48, 0x8D, 0x2D, 0x00, 0x00, 0x00, 0x00}}, + {x86.RSI, 0, []byte{0x48, 0x8D, 0x35, 0x00, 0x00, 0x00, 0x00}}, + {x86.RDI, 0, []byte{0x48, 0x8D, 0x3D, 0x00, 0x00, 0x00, 0x00}}, + {x86.R8, 0, []byte{0x4C, 0x8D, 0x05, 0x00, 0x00, 0x00, 0x00}}, + {x86.R9, 0, []byte{0x4C, 0x8D, 0x0D, 0x00, 0x00, 0x00, 0x00}}, + {x86.R10, 0, []byte{0x4C, 0x8D, 0x15, 0x00, 0x00, 0x00, 0x00}}, + {x86.R11, 0, []byte{0x4C, 0x8D, 0x1D, 0x00, 0x00, 0x00, 0x00}}, + {x86.R12, 0, []byte{0x4C, 0x8D, 0x25, 0x00, 0x00, 0x00, 0x00}}, + {x86.R13, 0, []byte{0x4C, 0x8D, 0x2D, 0x00, 0x00, 0x00, 0x00}}, + {x86.R14, 0, []byte{0x4C, 0x8D, 0x35, 0x00, 0x00, 0x00, 0x00}}, + {x86.R15, 0, []byte{0x4C, 0x8D, 0x3D, 0x00, 0x00, 0x00, 0x00}}, + } + + for _, pattern := range usagePatterns { + t.Logf("lea %s, [rip+%d]", pattern.Destination, pattern.Offset) + code := x86.LoadAddress(nil, pattern.Destination, pattern.Offset) + assert.DeepEqual(t, code, pattern.Code) + } +}