v1 omf support (-1), improved big endian support, -S to convert PAGE0 to a stack segment.

This commit is contained in:
Kelvin Sherlock 2022-12-15 21:13:08 -05:00
parent 65d373be25
commit a455e48a2b
3 changed files with 150 additions and 20 deletions

View File

@ -41,8 +41,6 @@
struct { struct {
bool v = false; bool v = false;
bool C = false;
bool X = false;
bool S = false; bool S = false;
std::string o; std::string o;
@ -50,8 +48,10 @@ struct {
std::vector<std::string> L; std::vector<std::string> L;
unsigned errors = 0; unsigned errors = 0;
uint16_t file_type; uint16_t file_type = 0;
uint32_t aux_type; uint32_t aux_type = 0;
unsigned omf_flags = 0;
} flags; } flags;
@ -1672,14 +1672,19 @@ int main(int argc, char **argv) {
int c; int c;
while ((c = getopt(argc, argv, "vCXL:l:o:t:")) != -1) { while ((c = getopt(argc, argv, "vCXSL:l:o:t:")) != -1) {
switch(c) { switch(c) {
case 'h': usage(0); break; case 'h': usage(0); break;
case 'v': flags.v = true; break; case 'v': flags.v = true; break;
case 'X': flags.X = true; break; case 'S': flags.S = true; break;
case 'C': flags.C = true; break;
case '1': flags.omf_flags |= OMF_V1; break;
case 'X': flags.omf_flags |= OMF_NO_EXPRESS; break;
case 'C': flags.omf_flags |= OMF_NO_SUPER; break;
case 'o': flags.o = optarg; break; case 'o': flags.o = optarg; break;
case 'l': { case 'l': {
if (*optarg) flags.l.emplace_back(optarg); if (*optarg) flags.l.emplace_back(optarg);
break; break;
@ -1775,10 +1780,9 @@ int main(int argc, char **argv) {
flags.file_type = 0xb3; flags.file_type = 0xb3;
} }
void save_omf(const std::string &path, std::vector<omf::segment> &segments, bool compress, bool expressload);
int set_file_type(const std::string &path, uint16_t file_type, uint32_t aux_type); int set_file_type(const std::string &path, uint16_t file_type, uint32_t aux_type);
save_omf(flags.o, omf_segments, !flags.C, !flags.X); save_omf(flags.o, omf_segments, flags.omf_flags);
set_file_type(flags.o, flags.file_type, flags.aux_type); set_file_type(flags.o, flags.file_type, flags.aux_type);
} }

134
omf.cpp
View File

@ -17,6 +17,18 @@
#define O_BINARY 0 #define O_BINARY 0
#endif #endif
enum class endian {
#ifdef _WIN32
little = 0,
big = 1,
native = little
#else
little = __ORDER_LITTLE_ENDIAN__,
big = __ORDER_BIG_ENDIAN__,
native = __BYTE_ORDER__
#endif
};
#pragma pack(push, 1) #pragma pack(push, 1)
struct omf_header { struct omf_header {
uint32_t bytecount = 0; uint32_t bytecount = 0;
@ -66,6 +78,87 @@ struct omf_express_header {
static_assert(sizeof(omf_header) == 44, "OMF Header not packed"); static_assert(sizeof(omf_header) == 44, "OMF Header not packed");
static_assert(sizeof(omf_express_header) == 48, "OMF Express Header not packed"); static_assert(sizeof(omf_express_header) == 48, "OMF Express Header not packed");
static void swap(uint8_t &x) {}
static void swap(uint16_t &x) {
#if defined(__GNUC__)
x = __builtin_bswap16(x);
#else
x = (x >> 8) | (x << 8);
#endif
}
static void swap(uint32_t &x) {
#if defined(__GNUC__)
x = __builtin_bswap32(x);
#else
x = ((x & 0xff000000) >> 24) |
((x & 0x00ff0000) >> 8) |
((x & 0x0000ff00) << 8) |
((x & 0x000000ff) << 24);
#endif
}
static void to_little(struct omf_header &h) {
if (endian::native != endian::little) {
swap(h.bytecount);
swap(h.reserved_space);
swap(h.length);
swap(h.unused1);
swap(h.lablen);
swap(h.numlen);
swap(h.version);
swap(h.banksize);
swap(h.kind);
swap(h.unused2);
swap(h.org);
swap(h.alignment);
swap(h.numsex);
swap(h.unused3);
swap(h.segnum);
swap(h.entry);
swap(h.dispname);
swap(h.dispdata);
}
}
static void to_little(struct omf_express_header &h) {
if (endian::native != endian::little) {
swap(h.lconst_mark);
swap(h.lconst_size);
swap(h.reloc_mark);
swap(h.reloc_size);
swap(h.unused1);
swap(h.lablen);
swap(h.numlen);
swap(h.version);
swap(h.banksize);
swap(h.kind);
swap(h.unused2);
swap(h.org);
swap(h.alignment);
swap(h.numsex);
swap(h.unused3);
swap(h.segnum);
swap(h.entry);
swap(h.dispname);
swap(h.dispdata);
}
}
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<uint8_t> &v, uint8_t x) { void push(std::vector<uint8_t> &v, uint8_t x) {
v.push_back(x); v.push_back(x);
} }
@ -194,7 +287,7 @@ enum {
SUPER_INTERSEG36, SUPER_INTERSEG36,
}; };
uint32_t add_relocs(std::vector<uint8_t> &data, size_t data_offset, omf::segment &seg, bool compress) { uint32_t add_relocs(std::vector<uint8_t> &data, size_t data_offset, omf::segment &seg, bool compress, bool super) {
std::array< optional<super_helper>, 38 > ss; std::array< optional<super_helper>, 38 > ss;
@ -203,9 +296,9 @@ uint32_t add_relocs(std::vector<uint8_t> &data, size_t data_offset, omf::segment
for (auto &r : seg.relocs) { 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) { if (r.shift == 0 && r.size == 2) {
constexpr int n = SUPER_RELOC2; constexpr int n = SUPER_RELOC2;
@ -267,9 +360,9 @@ uint32_t add_relocs(std::vector<uint8_t> &data, size_t data_offset, omf::segment
} }
for (const auto &r : seg.intersegs) { 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) { if (r.shift == 0 && r.size == 3) {
constexpr int n = SUPER_INTERSEG1; constexpr int n = SUPER_INTERSEG1;
@ -384,7 +477,7 @@ void save_bin(const std::string &path, omf::segment &segment, uint32_t org) {
} }
void save_omf(const std::string &path, std::vector<omf::segment> &segments, bool compress, bool expressload) { void save_omf(const std::string &path, std::vector<omf::segment> &segments, unsigned flags) {
// expressload doesn't support links to other files. // expressload doesn't support links to other files.
// fortunately, we don't either. // fortunately, we don't either.
@ -392,6 +485,17 @@ void save_omf(const std::string &path, std::vector<omf::segment> &segments, bool
std::vector<uint8_t> expr_headers; std::vector<uint8_t> expr_headers;
std::vector<unsigned> expr_offsets; std::vector<unsigned> expr_offsets;
bool compress = !(flags & OMF_NO_COMPRESS);
bool super = !(flags & OMF_NO_SUPER);
bool expressload = !(flags & OMF_NO_EXPRESS);
bool v1 = flags & OMF_V1;
if (v1) {
expressload = false;
super = false;
}
int fd; int fd;
fd = open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666); fd = open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
if (fd < 0) { if (fd < 0) {
@ -470,17 +574,13 @@ void save_omf(const std::string &path, std::vector<omf::segment> &segments, bool
uint32_t reloc_offset = offset + sizeof(omf_header) + data.size(); uint32_t reloc_offset = offset + sizeof(omf_header) + data.size();
uint32_t reloc_size = 0; uint32_t reloc_size = 0;
reloc_size = add_relocs(data, data_offset, s, compress); reloc_size = add_relocs(data, data_offset, s, compress, super);
// end-of-record // end-of-record
push(data, (uint8_t)omf::END); push(data, (uint8_t)omf::END);
h.bytecount = data.size() + sizeof(omf_header); h.bytecount = data.size() + sizeof(omf_header);
// todo -- byteswap to little-endian!
offset += write(fd, &h, sizeof(h));
offset += write(fd, data.data(), data.size());
if (expressload) { if (expressload) {
expr_offsets.emplace_back(expr_headers.size()); expr_offsets.emplace_back(expr_headers.size());
@ -514,6 +614,17 @@ void save_omf(const std::string &path, std::vector<omf::segment> &segments, bool
push(expr_headers, s.segname); push(expr_headers, s.segname);
} }
if (v1) to_v1(h);
to_little(h);
offset += write(fd, &h, sizeof(h));
offset += write(fd, data.data(), data.size());
// version 1 needs 512-byte padding for all but final segment.
if (v1 && &s != &segments.back()) {
static uint8_t zero[512];
offset += write(fd, zero, 512 - (offset & 511) );
}
} }
if (expressload) { if (expressload) {
@ -553,6 +664,7 @@ void save_omf(const std::string &path, std::vector<omf::segment> &segments, bool
h.bytecount = data.size() + sizeof(omf_header); h.bytecount = data.size() + sizeof(omf_header);
to_little(h);
lseek(fd, 0, SEEK_SET); lseek(fd, 0, SEEK_SET);
write(fd, &h, sizeof(h)); write(fd, &h, sizeof(h));
write(fd, data.data(), data.size()); write(fd, data.data(), data.size());

14
omf.h
View File

@ -5,6 +5,7 @@
#include <vector> #include <vector>
#include <string> #include <string>
namespace omf { namespace omf {
enum opcode : uint8_t { enum opcode : uint8_t {
@ -78,4 +79,17 @@ namespace omf {
} }
enum {
// flags
OMF_V1 = 1,
OMF_V2 = 0,
OMF_NO_SUPER = 2,
OMF_NO_COMPRESS = 4,
OMF_NO_EXPRESS = 8
};
void save_omf(const std::string &path, std::vector<omf::segment> &segments, unsigned flags);
#endif #endif