package asmc import ( "encoding/binary" "fmt" "slices" "git.urbach.dev/cli/q/src/config" "git.urbach.dev/cli/q/src/fs" "git.urbach.dev/cli/q/src/sizeof" ) // resolvePointers resolves the addresses of all pointers within the code and writes the correct addresses to the code slice. func (c *compiler) resolvePointers() { restart: for i, pointer := range c.codePointers { address := pointer.Resolve() if sizeof.Signed(int32(address)) > int(pointer.Size) { left := c.code[:pointer.Position-Address(pointer.OpSize)] right := c.code[pointer.Position+Address(pointer.Size):] size := pointer.Size + pointer.OpSize opCode := c.code[pointer.Position-Address(pointer.OpSize)] var jump []byte switch opCode { case 0x74: // JE jump = []byte{0x0F, 0x84} case 0x75: // JNE jump = []byte{0x0F, 0x85} case 0x7C: // JL jump = []byte{0x0F, 0x8C} case 0x7D: // JGE jump = []byte{0x0F, 0x8D} case 0x7E: // JLE jump = []byte{0x0F, 0x8E} case 0x7F: // JG jump = []byte{0x0F, 0x8F} case 0xEB: // JMP jump = []byte{0xE9} default: panic(fmt.Sprintf("failed to increase pointer size for instruction 0x%x", opCode)) } pointer.Position += Address(len(jump) - int(pointer.OpSize)) pointer.OpSize = uint8(len(jump)) pointer.Size = 4 jump = binary.LittleEndian.AppendUint32(jump, uint32(address)) offset := Address(len(jump)) - Address(size) for _, following := range c.codePointers[i+1:] { following.Position += offset } for key, address := range c.codeLabels { if address > pointer.Position { c.codeLabels[key] += offset } } c.code = slices.Concat(left, jump, right) goto restart } slice := c.code[pointer.Position : pointer.Position+Address(pointer.Size)] switch pointer.Size { case 1: slice[0] = uint8(address) case 2: binary.LittleEndian.PutUint16(slice, uint16(address)) case 4: binary.LittleEndian.PutUint32(slice, uint32(address)) case 8: binary.LittleEndian.PutUint64(slice, uint64(address)) } } dataStart, _ := fs.Align(c.codeStart+Address(len(c.code)), config.Align) for _, pointer := range c.dataPointers { address := config.BaseAddress + dataStart + pointer.Resolve() + 8 slice := c.code[pointer.Position : pointer.Position+4] binary.LittleEndian.PutUint32(slice, uint32(address)) } if config.TargetOS == config.Windows { importsStart, _ := fs.Align(dataStart+Address(len(c.data)), config.Align) for _, pointer := range c.dllPointers { destination := importsStart + pointer.Resolve() from := c.codeStart + pointer.Position + Address(pointer.Size) offset := destination - from slice := c.code[pointer.Position : pointer.Position+4] binary.LittleEndian.PutUint32(slice, uint32(offset)) } } }