diff --git a/link.cpp b/link.cpp index 8ddbed2..e274ff9 100644 --- a/link.cpp +++ b/link.cpp @@ -30,7 +30,7 @@ #include "link.h" #include "script.h" -void save_omf(const std::string &path, std::vector &segments, bool compress, bool expressload); +void save_omf(const std::string &path, std::vector &segments, bool compress, bool expressload, unsigned version = 2); void save_bin(const std::string &path, omf::segment &segment); int set_file_type(const std::string &path, uint16_t file_type, uint32_t aux_type, std::error_code &ec); @@ -1255,7 +1255,7 @@ void evaluate(label_t label, opcode_t opcode, const char *cursor) { /* OMF version, 1 or 2 */ uint32_t value = number_operand(cursor, local_symbol_table); - if (value != 2) + if (value < 1 || value > 2) throw std::runtime_error("bad OMF version"); ver = value; break; diff --git a/omf.cpp b/omf.cpp index 91a7ec1..828190e 100644 --- a/omf.cpp +++ b/omf.cpp @@ -32,20 +32,20 @@ enum class endian { #pragma pack(push, 1) struct omf_header { - uint32_t bytecount = 0; + uint32_t bytecount = 0; // block count in v1 uint32_t reserved_space = 0; uint32_t length = 0; - uint8_t unused1 = 0; + uint8_t unused1 = 0; // kind in v1 uint8_t lablen = 0; uint8_t numlen = 4; uint8_t version = 2; uint32_t banksize = 0; - uint16_t kind = 0; + uint16_t kind = 0; // unused in v1 uint16_t unused2 = 0; uint32_t org = 0; uint32_t alignment = 0; uint8_t numsex = 0; - uint8_t unused3 = 0; + uint8_t unused3 = 0; // lcbank in v1 uint16_t segnum = 0; uint32_t entry = 0; uint16_t dispname = 0; @@ -74,6 +74,7 @@ struct omf_express_header { uint16_t dispdata = 0; }; + #pragma pack(pop) static_assert(sizeof(omf_header) == 44, "OMF Header not packed"); @@ -160,6 +161,17 @@ static void to_little(struct omf_express_header &h) { } } +static void to_v1(struct omf_header &h) { + + // KIND op value used as-is, no translation. + + h.version = 1; + // byte count -> block count + h.bytecount = (h.bytecount + 511) >> 9; + h.unused1 = h.kind; + h.kind = 0; +} + void push(std::vector &v, uint8_t x) { v.push_back(x); } @@ -288,7 +300,7 @@ enum { SUPER_INTERSEG36, }; -uint32_t add_relocs(std::vector &data, size_t data_offset, omf::segment &seg, bool compress) { +uint32_t add_relocs(std::vector &data, size_t data_offset, omf::segment &seg, bool compress, bool super) { std::array< std::optional, 38 > ss; @@ -297,9 +309,9 @@ uint32_t add_relocs(std::vector &data, size_t data_offset, omf::segment for (auto &r : seg.relocs) { - if (r.can_compress()) { + if (compress && r.can_compress()) { - if (compress) { + if (super) { if (r.shift == 0 && r.size == 2) { constexpr int n = SUPER_RELOC2; @@ -361,9 +373,9 @@ uint32_t add_relocs(std::vector &data, size_t data_offset, omf::segment } for (const auto &r : seg.intersegs) { - if (r.can_compress()) { + if (compress && r.can_compress()) { - if (compress) { + if (super) { if (r.shift == 0 && r.size == 3) { constexpr int n = SUPER_INTERSEG1; @@ -516,11 +528,21 @@ void save_object(const std::string &path, omf::segment &s, uint32_t length) { close(fd); } -void save_omf(const std::string &path, std::vector &segments, bool compress, bool expressload) { +void save_omf(const std::string &path, std::vector &segments, bool compress, bool expressload, unsigned version) { // expressload doesn't support links to other files. // fortunately, we don't either. + // "compress" really means SUPER, not cRELOC/cINTERSEG + + + // version 1 OMF lacks support for SUPER records or expressload. + + if (version == 1) { + compress = false; + expressload = false; + } + std::vector expr_headers; std::vector expr_offsets; @@ -603,7 +625,7 @@ void save_omf(const std::string &path, std::vector &segments, bool uint32_t reloc_offset = offset + sizeof(omf_header) + data.size(); uint32_t reloc_size = 0; - reloc_size = add_relocs(data, data_offset, s, compress); + reloc_size = add_relocs(data, data_offset, s, true, compress); // end-of-record push(data, (uint8_t)omf::END); @@ -643,6 +665,7 @@ void save_omf(const std::string &path, std::vector &segments, bool push(expr_headers, s.segname); } + if (version == 1) to_v1(h); to_little(h); offset += write(fd, &h, sizeof(h)); offset += write(fd, data.data(), data.size());