From f414da58a3c4f20f791d70a692234c038fc0d0a2 Mon Sep 17 00:00:00 2001 From: Rohan Padhye Date: Tue, 16 Oct 2018 21:53:31 -0700 Subject: [PATCH] Add support for relocatable data words --- src/main/kotlin/venus/assembler/Assembler.kt | 19 ++++++--- src/main/kotlin/venus/linker/Linker.kt | 32 +++++++++++++++ src/main/kotlin/venus/riscv/Program.kt | 21 ++++++++++ src/test/kotlin/assembler/LinkerTest.kt | 42 ++++++++++++++++++++ 4 files changed, 109 insertions(+), 5 deletions(-) diff --git a/src/main/kotlin/venus/assembler/Assembler.kt b/src/main/kotlin/venus/assembler/Assembler.kt index ea3caa7b..24b3970a 100644 --- a/src/main/kotlin/venus/assembler/Assembler.kt +++ b/src/main/kotlin/venus/assembler/Assembler.kt @@ -173,11 +173,20 @@ internal class AssemblerPassOne(private val text: String) { ".word" -> { for (arg in args) { - val word = userStringToInt(arg) - prog.addToData(word.toByte()) - prog.addToData((word shr 8).toByte()) - prog.addToData((word shr 16).toByte()) - prog.addToData((word shr 24).toByte()) + try { + val word = userStringToInt(arg) + prog.addToData(word.toByte()) + prog.addToData((word shr 8).toByte()) + prog.addToData((word shr 16).toByte()) + prog.addToData((word shr 24).toByte()) + } catch (e: NumberFormatException) { + /* arg is not a number; interpret as label */ + prog.addDataRelocation(arg, currentDataOffset - MemorySegments.STATIC_BEGIN) + prog.addToData(0) + prog.addToData(0) + prog.addToData(0) + prog.addToData(0) + } currentDataOffset += 4 } } diff --git a/src/main/kotlin/venus/linker/Linker.kt b/src/main/kotlin/venus/linker/Linker.kt index ee30a632..09f0d5c4 100644 --- a/src/main/kotlin/venus/linker/Linker.kt +++ b/src/main/kotlin/venus/linker/Linker.kt @@ -14,6 +14,14 @@ import venus.riscv.insts.dsl.relocators.Relocator */ data class RelocationInfo(val relocator: Relocator, val offset: Int, val label: String) +/** + * Describes how to relocate data bytes + * + * @param offset the byte offset in the data segment + * @param label the target label + */ +data class DataRelocationInfo(val offset: Int, val label: String) + /** * A singleton which links a list of programs into one program. * @@ -39,6 +47,7 @@ object Linker { val linkedProgram = LinkedProgram() val globalTable = HashMap() val toRelocate = ArrayList() + val toRelocateData = ArrayList() var textTotalOffset = 0 var dataTotalOffset = 0 @@ -81,6 +90,20 @@ object Linker { } } + for ((offset, label) in prog.dataRelocationTable) { + val toAddress = prog.labels.get(label) + val location = dataTotalOffset + offset + if (toAddress != null) { + linkedProgram.prog.overwriteData(location, toAddress.toByte()) + linkedProgram.prog.overwriteData(location + 1, (toAddress shr 8).toByte()) + linkedProgram.prog.overwriteData(location + 2, (toAddress shr 16).toByte()) + linkedProgram.prog.overwriteData(location + 3, (toAddress shr 24).toByte()) + } else { + /* need to relocate globally */ + toRelocateData.add(DataRelocationInfo(location, label)) + } + } + textTotalOffset += prog.textSize dataTotalOffset += prog.dataSize } @@ -93,6 +116,15 @@ object Linker { relocator(mcode, offset, toAddress) } + for ((location, label) in toRelocateData) { + val toAddress = globalTable.get(label) ?: + throw AssemblerError("label $label used but not defined") + linkedProgram.prog.overwriteData(location, toAddress.toByte()) + linkedProgram.prog.overwriteData(location + 1, (toAddress shr 8).toByte()) + linkedProgram.prog.overwriteData(location + 2, (toAddress shr 16).toByte()) + linkedProgram.prog.overwriteData(location + 3, (toAddress shr 24).toByte()) + } + return linkedProgram } } diff --git a/src/main/kotlin/venus/riscv/Program.kt b/src/main/kotlin/venus/riscv/Program.kt index 4d619891..e66e4d5d 100644 --- a/src/main/kotlin/venus/riscv/Program.kt +++ b/src/main/kotlin/venus/riscv/Program.kt @@ -1,6 +1,7 @@ package venus.riscv import venus.assembler.DebugInfo +import venus.linker.DataRelocationInfo import venus.linker.RelocationInfo import venus.riscv.insts.dsl.relocators.Relocator @@ -17,6 +18,7 @@ class Program(val name: String = "anonymous") { val debugInfo = ArrayList() val labels = HashMap() val relocationTable = ArrayList() + val dataRelocationTable = ArrayList() val dataSegment = ArrayList() var textSize = 0 var dataSize = 0 @@ -42,6 +44,16 @@ class Program(val name: String = "anonymous") { dataSize++ } + /** + * Overwrites a byte of data in the program's data segment + * + * @param offset the offset at which to overwrite + * @param byte the value to overwrite with + */ + fun overwriteData(offset: Int, byte: Byte) { + dataSegment[offset] = byte + } + /** * Adds debug info to the instruction currently being assembled. * @@ -86,6 +98,15 @@ class Program(val name: String = "anonymous") { fun addRelocation(relocator: Relocator, label: String, offset: Int = textSize) = relocationTable.add(RelocationInfo(relocator, offset, label)) + /** + * Adds a line to the data relocation table. + * + * @param label the label to relocate + * @param offset the byte offset the label is at (from the start of the data section) + */ + fun addDataRelocation(label: String, offset: Int = textSize) = + dataRelocationTable.add(DataRelocationInfo(offset, label)) + /** * Makes a label global. * diff --git a/src/test/kotlin/assembler/LinkerTest.kt b/src/test/kotlin/assembler/LinkerTest.kt index e57b1a53..5da472fb 100644 --- a/src/test/kotlin/assembler/LinkerTest.kt +++ b/src/test/kotlin/assembler/LinkerTest.kt @@ -116,4 +116,46 @@ class LinkerTest { assertTrue(true) } } + + @Test fun dataRelocation() { + val (prog, _) = Assembler.assemble(""" + .data + A: + .word 42 + B: + .word A + .text + la x1, A + lw x2, B + lw x3, 0(x2) + """) + val linked = Linker.link(listOf(prog)) + val sim = Simulator(linked) + sim.run() + assertEquals(sim.getReg(1), sim.getReg(2)) + assertEquals(42, sim.getReg(3)) + } + + @Test fun dataRelocationAcrossFiles() { + val (prog1, _) = Assembler.assemble(""" + .data + .globl A + .globl B + A: + .word 42 + B: + .word A + """) + val (prog2, _) = Assembler.assemble(""" + .text + la x1, A + lw x2, B + lw x3, 0(x2) + """) + val linked = Linker.link(listOf(prog1, prog2)) + val sim = Simulator(linked) + sim.run() + assertEquals(sim.getReg(1), sim.getReg(2)) + assertEquals(42, sim.getReg(3)) + } }