summaryrefslogtreecommitdiff
path: root/src/coff.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/coff.h')
-rw-r--r--src/coff.h156
1 files changed, 156 insertions, 0 deletions
diff --git a/src/coff.h b/src/coff.h
new file mode 100644
index 0000000..c91ef3c
--- /dev/null
+++ b/src/coff.h
@@ -0,0 +1,156 @@
+#pragma once
+
+/* SPDX-License-Identifier: Unlicense
+ *
+ * Common Object File Format loader implementation.
+ *
+ * A section "11. COMMON OBJECT FILE FORMAT (COFF)" from the document named
+ * "SYSTEM V/68 Release 3 Programmer's Guide" or "MU43715PG/D2" dated 12/01/87
+ * was used for reference to implement this functionality.
+ *
+ * A "TI-89 / TI-92 Plus Sierra C Assembler Reference Manual, Beta Version"
+ * dated "February 2, 2001" was used for reference to implement this
+ * functionality.
+ */
+
+#include "common.h"
+
+#include <cstdint>
+
+namespace COFF {
+
+constexpr size_t kFileHeaderSize = 20;
+constexpr size_t kOptionalHeaderSize = 28;
+constexpr size_t kSectionHeaderSize = 40;
+
+/// Relocation information stripped from the file
+constexpr uint16_t F_RELFG = 0x1;
+/// File is executable (i.be. no unresolved external references)
+constexpr uint16_t F_EXEC = 0x2;
+/// Line numbers stripped from the file
+constexpr uint16_t F_LNNO = 0x4;
+/// Local symbols stripped from the file
+constexpr uint16_t F_LSYMS = 0x8;
+/// Global symbols stripped from the file
+constexpr uint16_t F_GSYMS = 0x10;
+/// Error in object file
+constexpr uint16_t F_ERROR = 0x80;
+
+struct FileHeader {
+ uint16_t magic; ///< Magic number
+ /// Number of section headers (equals to number of sections)
+ uint16_t nsections;
+ /// Time and date stamp indicating when the file was created, expressed as
+ /// the number of elapsed seconds since 00:00:00 GMT, January 1, 1970
+ int32_t timedate;
+ /// File pointer containing the starting address of the symbol table
+ uint32_t symtable_offset;
+ uint32_t nsymbols; ///< Number of entries in the symbol table
+ uint16_t optional_header_nbytes; ///< Number of bytes in the optional header
+ uint16_t flags; ///< Flags (see F_* constexpr values)
+ static constexpr inline auto FromBytes(const uint8_t *data)
+ {
+ const bool be = true;
+ return FileHeader{
+ /* .magic */ GetU16(data + 0, be),
+ /* .nsections */ GetU16(data + 2, be),
+ /* .timedate */ GetI32(data + 4, be),
+ /* .symtable_offset */ GetU32(data + 8, be),
+ /* .nsymbols */ GetU32(data + 12, be),
+ /* .optional_header_nbytes */ GetU16(data + 16, be),
+ /* .flags */ GetU16(data + 18, be),
+ };
+ }
+ static constexpr uint16_t kMagicSierraM68k = 0x150;
+};
+
+struct OptionalHeader {
+ uint16_t magic; ///< Magic number
+ uint16_t version; ///< Version stamp
+ uint32_t tsize; ///< Size of text in bytes
+ uint32_t dsize; ///< Size of initialized data in bytes
+ uint32_t bsize; ///< Size of uninitialized data in bytes
+ uint32_t entry; ///< Program entry point
+ uint32_t text_start; ///< Base address of text
+ uint32_t data_start; ///< Base address of data
+ static constexpr inline auto FromBytes(const uint8_t *data)
+ {
+ const bool be = true;
+ return OptionalHeader{
+ /* .magic */ GetU16(data + 0, be),
+ /* .version */ GetU16(data + 2, be),
+ /* .tsize */ GetU32(data + 4, be),
+ /* .dsize */ GetU32(data + 8, be),
+ /* .bsize */ GetU32(data + 12, be),
+ /* .entry */ GetU32(data + 16, be),
+ /* .text_start */ GetU32(data + 20, be),
+ /* .data_start */ GetU32(data + 24, be),
+ };
+ }
+};
+
+enum class SectionType: uint32_t {
+ /// Regular section (allocated, relocated, loaded)
+ Regular = 0,
+ /// Dummy section (not allocated, relocated, not loaded)
+ Dummy = 0x1,
+ /// Noload section (allocated, relocated, not loaded)
+ NoLoad = 0x2,
+ /// Grouped section (formed from input sections)
+ Grouped = 0x4,
+ /// Padding section (not allocated, not relocated, loaded)
+ Padding = 0x8,
+ /// Copy section (for a decision function used in updating fields; not
+ /// allocated, not relocated, loaded, relocation and line number entries
+ /// processed normally)
+ Copy = 0x10,
+ /// Section contains executable text
+ Text = 0x20,
+ /// Section contains initialized data
+ Data = 0x40,
+ /// Section contains only uninitialized data
+ Bss = 0x80,
+ /// Section contains ORG'd (absolute) data
+ Org = 0x100,
+ /// Comment section (not allocated, not relocated, not loaded)
+ Info = 0x200,
+ /// Overlay section (not allocated, relocated, not loaded)
+ Overlay = 0x400,
+ /// For .lib section (treated like STYP_INFO)
+ Lib = 0x800,
+};
+
+struct SectionHeader {
+ char name[8]; ///< 8-character null-padded section name
+ uint32_t paddr; ///< Physical address of section
+ uint32_t vaddr; ///< Virtual address of section
+ uint32_t size; ///< Seciton size in bytes
+ uint32_t section_offset; ///< File pointer to raw data
+ uint32_t reloc_offset; ///< File pointer to relocation entries
+ uint32_t lineno_offset; ///< File pointer to line number entries
+ uint16_t nreloc; ///< Number of relocation entries
+ uint16_t nlineno; ///< Number of line number entries
+ uint32_t flags; ///< Flags (see STYP_* constexpr values)
+ static constexpr inline auto FromBytes(const void *data)
+ {
+ const uint8_t *d = static_cast<const uint8_t *>(data);
+ const char *c = static_cast<const char *>(data);
+ const bool be = true;
+ return SectionHeader{
+ /* .name */ {
+ c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7],
+ },
+ /* .paddr */ GetU32(d + 8, be),
+ /* .vaddr */ GetU32(d + 12, be),
+ /* .size */ GetU32(d + 16, be),
+ /* .section_offset */ GetU32(d + 20, be),
+ /* .reloc_offset */ GetU32(d + 24, be),
+ /* .lineno_offset */ GetU32(d + 28, be),
+ /* .nreloc */ GetU16(d + 32, be),
+ /* .nlineno */ GetU16(d + 34, be),
+ /* .flags */ GetU32(d + 36, be),
+ };
+ }
+};
+
+}