summaryrefslogtreecommitdiff
path: root/src/coff.h
blob: c91ef3c8c2fae74101d356f549a7c90c13a6198e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
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),
        };
    }
};

}