55 lines
1.4 KiB
Ruby
55 lines
1.4 KiB
Ruby
require_relative 'assembler'
|
|
|
|
module Asm
|
|
module Arm
|
|
|
|
# Relocation constants
|
|
# Note that in this assembler, a relocation simply means any
|
|
# reference to a label that can only be determined at assembly time
|
|
# or later (as in the normal meaning)
|
|
|
|
R_ARM_PC24 = 0x01
|
|
R_ARM_ABS32 = 0x02
|
|
|
|
# Unofficial (cant be used for extern relocations)
|
|
R_ARM_PC12 = 0xF0
|
|
|
|
# TODO actually find the closest somehow
|
|
def self.closest_addrtable(as)
|
|
as.objects.find do |obj|
|
|
obj.is_a?(Asm::ARM::AddrTableObject)
|
|
end || (raise Asm::AssemblyError.new('could not find addrtable to use', nil))
|
|
end
|
|
|
|
def self.write_resolved_relocation(io, addr, type)
|
|
case type
|
|
when R_ARM_PC24
|
|
diff = addr - io.tell - 8
|
|
packed = [diff >> 2].pack('l')
|
|
io << packed[0,3]
|
|
when R_ARM_ABS32
|
|
packed = [addr].pack('l')
|
|
io << packed
|
|
when R_ARM_PC12
|
|
diff = addr - io.tell - 8
|
|
if (diff.abs > 2047)
|
|
raise Asm::AssemblyError.new('offset too large for R_ARM_PC12 relocation',
|
|
nil)
|
|
end
|
|
|
|
val = diff.abs
|
|
sign = (diff>0)?1:0
|
|
|
|
curr = io.read_uint32
|
|
io.seek(-4, IO::SEEK_CUR)
|
|
|
|
io.write_uint32 (curr & ~0b00000000100000000000111111111111) |
|
|
val | (sign << 23)
|
|
else
|
|
raise 'unknown relocation type'
|
|
end
|
|
end
|
|
|
|
end
|
|
|