summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Qin <richard.qin.x@gmail.com>2026-05-13 15:34:19 +0800
committerRichard Qin <richard.qin.x@gmail.com>2026-05-13 15:34:19 +0800
commit555d7be72c7c3a08b74f4d4afa4dcc6dd8da8271 (patch)
treeb746cb92195c2bc2dab2491d800f73f62a919e3e
parente5d267d35504a831855d73d8d49014f8c20c9a8a (diff)
downloadlume-555d7be72c7c3a08b74f4d4afa4dcc6dd8da8271.tar.gz
lume-555d7be72c7c3a08b74f4d4afa4dcc6dd8da8271.tar.xz
feat: add relocation header and implementation for RISC-V architecture
-rw-r--r--na/arch/riscv/relocate.cc100
-rw-r--r--na/include/lume/relocate.h53
2 files changed, 153 insertions, 0 deletions
diff --git a/na/arch/riscv/relocate.cc b/na/arch/riscv/relocate.cc
new file mode 100644
index 0000000..0216827
--- /dev/null
+++ b/na/arch/riscv/relocate.cc
@@ -0,0 +1,100 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* Copyright (C) 2026 Richard Qin */
+
+#include <lume/relocate.h>
+
+static inline bool range_ok(uint64 offset, uint64 size, uint64 image_size)
+{
+ if (offset > image_size) {
+ return false;
+ }
+ if (size > image_size - offset) {
+ return false;
+ }
+ return true;
+}
+
+RelocStatus relocate_apply(uint64 load_base, uint64 image_size,
+ uint64 link_base, const void* reloc_blob,
+ uint64 reloc_size)
+{
+ if (!reloc_blob || reloc_size == 0) {
+ return RELOC_OK;
+ }
+ if (reloc_size < sizeof(RelocTableHeader)) {
+ return RELOC_ERR_SIZE;
+ }
+
+ const auto* hdr = reinterpret_cast<const RelocTableHeader*>(reloc_blob);
+ if (hdr->magic != kRelocTableMagic) {
+ return RELOC_ERR_MAGIC;
+ }
+ if (hdr->version != kRelocTableVersion) {
+ return RELOC_ERR_VERSION;
+ }
+ if (hdr->arch != RELOC_ARCH_RISCV) {
+ return RELOC_ERR_ARCH;
+ }
+ if (hdr->entry_size < sizeof(RelocEntry) || (hdr->entry_size % 8) != 0) {
+ return RELOC_ERR_SIZE;
+ }
+
+ uint64 max_entries = (reloc_size - sizeof(RelocTableHeader)) /
+ static_cast<uint64>(hdr->entry_size);
+ if (hdr->entry_count > max_entries) {
+ return RELOC_ERR_SIZE;
+ }
+
+ if (image_size < sizeof(uint64)) {
+ return RELOC_ERR_RANGE;
+ }
+
+ const uint64 delta = load_base - link_base;
+ const uint8* p = reinterpret_cast<const uint8*>(reloc_blob) +
+ sizeof(RelocTableHeader);
+
+ for (uint32 i = 0; i < hdr->entry_count; ++i) {
+ const auto* ent = reinterpret_cast<const RelocEntry*>(p);
+ if ((ent->offset & 0x7) != 0 ||
+ !range_ok(ent->offset, sizeof(uint64), image_size)) {
+ return RELOC_ERR_RANGE;
+ }
+
+ uint64* target = reinterpret_cast<uint64*>(load_base + ent->offset);
+ switch (ent->type) {
+ case RELOC_RISCV_RELATIVE:
+ *target = load_base + ent->addend;
+ break;
+ case RELOC_RISCV_64:
+ *target = ent->addend + delta;
+ break;
+ default:
+ return RELOC_ERR_UNSUPPORTED;
+ }
+ p += hdr->entry_size;
+ }
+
+ return RELOC_OK;
+}
+
+const char* reloc_status_str(RelocStatus st)
+{
+ switch (st) {
+ case RELOC_OK:
+ return "ok";
+ case RELOC_ERR_MAGIC:
+ return "bad magic";
+ case RELOC_ERR_VERSION:
+ return "bad version";
+ case RELOC_ERR_ARCH:
+ return "arch mismatch";
+ case RELOC_ERR_SIZE:
+ return "size mismatch";
+ case RELOC_ERR_RANGE:
+ return "range";
+ case RELOC_ERR_UNSUPPORTED:
+ return "unsupported";
+ default:
+ return "unknown";
+ }
+}
diff --git a/na/include/lume/relocate.h b/na/include/lume/relocate.h
new file mode 100644
index 0000000..120824f
--- /dev/null
+++ b/na/include/lume/relocate.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* Copyright (C) 2026 Richard Qin */
+
+#pragma once
+
+#include <lume/types.h>
+
+inline constexpr uint64 kRelocTableMagic = 0x4C554D45524C4F43ULL; /* LUMERLOC */
+inline constexpr uint16 kRelocTableVersion = 1;
+
+enum RelocArch : uint16 {
+ RELOC_ARCH_RISCV = 1,
+ RELOC_ARCH_AARCH64 = 2,
+ RELOC_ARCH_X86_64 = 3,
+};
+
+enum RelocType : uint32 {
+ RELOC_RISCV_RELATIVE = 1,
+ RELOC_RISCV_64 = 2,
+};
+
+struct RelocTableHeader {
+ uint64 magic;
+ uint16 version;
+ uint16 arch;
+ uint32 entry_size;
+ uint32 entry_count;
+ uint32 reserved;
+};
+
+struct RelocEntry {
+ uint64 offset;
+ uint64 addend;
+ uint32 type;
+ uint32 reserved;
+};
+
+enum RelocStatus : uint32 {
+ RELOC_OK = 0,
+ RELOC_ERR_MAGIC,
+ RELOC_ERR_VERSION,
+ RELOC_ERR_ARCH,
+ RELOC_ERR_SIZE,
+ RELOC_ERR_RANGE,
+ RELOC_ERR_UNSUPPORTED,
+};
+
+/* Apply relocations to the image loaded at load_base. */
+RelocStatus relocate_apply(uint64 load_base, uint64 image_size,
+ uint64 link_base, const void* reloc_blob,
+ uint64 reloc_size);
+
+const char* reloc_status_str(RelocStatus st);