100 lines
2.7 KiB
Go
100 lines
2.7 KiB
Go
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))
|
|
}
|
|
}
|
|
}
|