mirror of
https://github.com/ksherlock/merlin-utils.git
synced 2024-06-16 05:29:35 +00:00
initial WIP
This commit is contained in:
commit
5159061ff0
24
Makefile
Normal file
24
Makefile
Normal file
|
@ -0,0 +1,24 @@
|
|||
LINK.o = $(LINK.cc)
|
||||
CXXFLAGS = -std=c++17 -g -Wall -Wno-sign-compare
|
||||
CCFLAGS = -g
|
||||
|
||||
.PHONY: all
|
||||
|
||||
all: rel-link
|
||||
|
||||
|
||||
o:
|
||||
mkdir $<
|
||||
|
||||
rel-link: o/link.o o/mapped_file.o o/omf.o
|
||||
$(LINK.o) $^ $(LDLIBS) -o $@
|
||||
|
||||
o/mapped_file.o : mapped_file.cpp mapped_file.h unique_resource.h
|
||||
o/link.o : link.cpp mapped_file.h omf.h
|
||||
o/omf.o : omf.cpp omf.h
|
||||
|
||||
o/%.o: %.cpp | o
|
||||
$(CXX) $(CXXFLAGS) -c -o $@ $<
|
||||
|
||||
%.cpp: %.re2c
|
||||
re2c -W -o $@ $<
|
261
link.cpp
Normal file
261
link.cpp
Normal file
|
@ -0,0 +1,261 @@
|
|||
/* c++17 */
|
||||
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
|
||||
#include "omf.h"
|
||||
|
||||
void save_omf(const std::string &path, std::vector<omf::segment> &segments, bool compress, bool expressload);
|
||||
|
||||
|
||||
struct symbol {
|
||||
std::string name;
|
||||
std::string file;
|
||||
uint32_t value = 0;
|
||||
unsigned id = 0;
|
||||
unsigned count = 0;
|
||||
|
||||
bool absolute = false;
|
||||
bool defined = false;
|
||||
};
|
||||
|
||||
struct pending_reloc : public omf::reloc {
|
||||
unsigned id = 0;
|
||||
};
|
||||
|
||||
std::unordered_map<std::string, unsigned> symbol_map;
|
||||
std::vector<symbol> symbol_table;
|
||||
|
||||
reference *find_symbol(const std::string &name) {
|
||||
|
||||
auto iter = symbol_map.find(name);
|
||||
if (iter != symbol_map.end()) return &symbol_table[*iter - 1];
|
||||
|
||||
unsigned id = symbol_table.size() + 1;
|
||||
symbol_map.emplace(name, id);
|
||||
|
||||
auto &rv = symbol_table.emplace_back();
|
||||
rv.name = name;
|
||||
rv.id = id;
|
||||
return *rv;
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint32_t start = 0; /* starting point of current unit */
|
||||
std::vector<unsigned> remap;
|
||||
|
||||
|
||||
process_labels(std::span &data) {
|
||||
|
||||
for(;;) {
|
||||
assert(data.size())
|
||||
unsigned flag = data[0];
|
||||
if (flag == 0x00) return;
|
||||
|
||||
unsigned length = flag & 0x1f;
|
||||
assert(length != 0);
|
||||
assert(data.size() >= length + 4);
|
||||
|
||||
std::string name(data.data() + 1, data.data() + 1 + length);
|
||||
data.remove_prefix(1 + length);
|
||||
uint32_t value = data[0] | (data[1] << 8) | (data[2] << 16);
|
||||
data.remove_prefix(3);
|
||||
|
||||
reference *e = find_symbol(name);
|
||||
switch (flag & ~0x1f) {
|
||||
case SYMBOL_EXTERNAL:
|
||||
/* map the unit symbol # to a global symbol # */
|
||||
value &= 0x7fff;
|
||||
if (remap.size() < value + 1)
|
||||
remap.resize(value + 1);
|
||||
remap[value] = e->id;
|
||||
break;
|
||||
|
||||
|
||||
case SYMBOL_ENTRY+SYMBOL_ABSOLUTE:
|
||||
if (e->defined && e->absolute && e->value == value)
|
||||
break; /* allow redef */
|
||||
|
||||
case SYMBOL_ENTRY:
|
||||
if (e->defined) {
|
||||
warnx("%s previously defined (%s)", e->name, e->file);
|
||||
break;
|
||||
}
|
||||
e->defined = true;
|
||||
e->file = file;
|
||||
if (flag & SYMBOL_ABSOLUTE) {
|
||||
e->absolute = true;
|
||||
e->value = value;
|
||||
} else {
|
||||
e->absolute = false;
|
||||
e->value = value - 0x8000 + start;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
process_reloc(std::span &data) {
|
||||
|
||||
for(;;) {
|
||||
assert(data.size());
|
||||
unsigned flag = data[0];
|
||||
if (flag == 0x00) return;
|
||||
|
||||
assert(data.size() >= 4);
|
||||
|
||||
uint32_t offset = data[1] | (data[2] << 8);
|
||||
unsigned x = data[3];
|
||||
data.remove_prefix(4);
|
||||
|
||||
offset += start;
|
||||
bool external = false;
|
||||
unsigned shift = 0;
|
||||
uint32_t value = 0;
|
||||
unsigned size = 0;
|
||||
|
||||
if (flag == 0xff) {
|
||||
/* shift */
|
||||
assert(data.size() >= 4);
|
||||
unsigned flag = data[0];
|
||||
value = data[1] | (data[2] << 8) | (data[3] << 16);
|
||||
value -= 0x8000;
|
||||
external = flag & 0x04;
|
||||
switch(flag & ~0x04) {
|
||||
case 0xd0:
|
||||
shift = 16;
|
||||
size = 1;
|
||||
break;
|
||||
case 0xd1:
|
||||
shift = 8;
|
||||
size = 2;
|
||||
break;
|
||||
case 0xd3:
|
||||
shift = 8;
|
||||
size = 1;
|
||||
break;
|
||||
default: /* bad */
|
||||
}
|
||||
} else {
|
||||
assert(flag & ~(0x0f|0x10|0x20|0x80) == 0);
|
||||
|
||||
unsigned size = 0;
|
||||
switch(flag & (0x80 + 0x20)) {
|
||||
case 0: size = 1;
|
||||
case 0x20: size = 3;
|
||||
case 0x80: size = 2;
|
||||
default: /* bad size */
|
||||
}
|
||||
external = flag & 0x10;
|
||||
|
||||
switch(size) {
|
||||
case 3: value |= seg_data[offset+2] << 16;
|
||||
case 2: value |= seg_data[offset+1] << 8;
|
||||
case 1: value |= seg_data[offset+0];
|
||||
}
|
||||
|
||||
|
||||
if (size > 1) value -= 0x8000;
|
||||
value += start;
|
||||
|
||||
}
|
||||
|
||||
/* external resolutions are deferred for later */
|
||||
|
||||
if (external) {
|
||||
/* x = local symbol # */
|
||||
reloc r;
|
||||
assert(x < remap.size());
|
||||
r.id = remap[x]; /* label reference is 0-based */
|
||||
r.size = size;
|
||||
r.offset = offset;
|
||||
r.value = value;
|
||||
r.shift = shift;
|
||||
|
||||
relocations.emplace_back(r);
|
||||
} else {
|
||||
uint32_t value = 0;
|
||||
omf::reloc r;
|
||||
r.size = size;
|
||||
r.offset = start;
|
||||
r.value = value;
|
||||
r.shift = shift;
|
||||
|
||||
seg.relocs.emplace_back(r);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void add_libraries() {
|
||||
auto iter = libs.begin();
|
||||
auto end = libs.end();
|
||||
|
||||
for(;;) {
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
process_unit(span data) {
|
||||
|
||||
/* skip over relocs, do symbols first */
|
||||
remap.clear();
|
||||
|
||||
span rr = data;
|
||||
for(;;) {
|
||||
if (data[0] == 0) break;
|
||||
data.remove_prefix(4);
|
||||
}
|
||||
data.remove_prefix(1);
|
||||
process_labels(data);
|
||||
assert(data.length() == 1);
|
||||
|
||||
/* now relocations */
|
||||
process_reloc(rr);
|
||||
}
|
||||
|
||||
|
||||
finalize(void) {
|
||||
|
||||
for (auto &r in relocations) {
|
||||
assert(r.id <= symbol_map.length());
|
||||
const auto &label = symbol_map[rr.id];
|
||||
|
||||
r.value = label.value;
|
||||
seg.relocs.emplace_back(r);
|
||||
}
|
||||
relocations.clear();
|
||||
}
|
||||
|
||||
void print_symbols(void) {
|
||||
|
||||
if (symbol_table.empty()) return;
|
||||
|
||||
/* alpha */
|
||||
std::sort(symbol_table.begin(), symbol_table.end(),
|
||||
[](const symbol &a, const symbol &b){
|
||||
return a.name < b.name;
|
||||
});
|
||||
|
||||
for (const auto &lab : symbol_table) {
|
||||
fprintf(stdout, "%-20s: $%06x\n", lab.name.c_str(), lab.value);
|
||||
}
|
||||
fputs("\n", stdout);
|
||||
/* numeric */
|
||||
std::sort(symbol_table.begin(), symbol_table.end(),
|
||||
[](const symbol &a, const symbol &b){
|
||||
return a.value < b.value;
|
||||
});
|
||||
|
||||
for (const auto &lab : symbol_table) {
|
||||
fprintf(stdout, "%-20s: $%06x\n", lab.name.c_str(), lab.value);
|
||||
}
|
||||
}
|
389
mapped_file.cpp
Normal file
389
mapped_file.cpp
Normal file
|
@ -0,0 +1,389 @@
|
|||
#include "mapped_file.h"
|
||||
#include "unique_resource.h"
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <system_error>
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
void set_or_throw_error(std::error_code *ec, int error, const std::string &what) {
|
||||
if (ec) *ec = std::error_code(error, std::system_category());
|
||||
else throw std::system_error(error, std::system_category(), what);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
|
||||
namespace {
|
||||
|
||||
/*
|
||||
* allocating a new string could reset GetLastError() to 0.
|
||||
*/
|
||||
void set_or_throw_error(std::error_code *ec, const char *what) {
|
||||
auto e = GetLastError();
|
||||
set_or_throw_error(ec, e, what);
|
||||
}
|
||||
|
||||
void set_or_throw_error(std::error_code *ec, const std::string &what) {
|
||||
auto e = GetLastError();
|
||||
set_or_throw_error(ec, e, what);
|
||||
}
|
||||
|
||||
|
||||
template<class ...Args>
|
||||
HANDLE CreateFileX(const std::string &s, Args... args) {
|
||||
return CreateFileA(s.c_str(), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<class ...Args>
|
||||
HANDLE CreateFileX(const std::wstring &s, Args... args) {
|
||||
return CreateFileW(s.c_str(), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void mapped_file_base::close() {
|
||||
if (is_open()) {
|
||||
|
||||
UnmapViewOfFile(_data);
|
||||
CloseHandle(_map_handle);
|
||||
CloseHandle(_file_handle);
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void mapped_file_base::open_common(const T& p, mapmode flags, size_t length, size_t offset, std::error_code *ec) {
|
||||
|
||||
if (ec) ec->clear();
|
||||
|
||||
HANDLE fh;
|
||||
HANDLE mh;
|
||||
|
||||
// length of 0 in CreateFileMapping / MapViewOfFile
|
||||
// means map the entire file.
|
||||
|
||||
if (is_open()) close();
|
||||
|
||||
fh = CreateFileX(p,
|
||||
flags == readonly ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ,
|
||||
nullptr,
|
||||
OPEN_EXISTING,
|
||||
flags == readonly ? FILE_ATTRIBUTE_READONLY : FILE_ATTRIBUTE_NORMAL,
|
||||
nullptr
|
||||
);
|
||||
if (fh == INVALID_HANDLE_VALUE)
|
||||
return set_or_throw_error(ec, "CreateFile");
|
||||
|
||||
auto fh_close = make_unique_resource(fh, CloseHandle);
|
||||
|
||||
|
||||
if (length == -1) {
|
||||
LARGE_INTEGER file_size;
|
||||
GetFileSizeEx(fh, &file_size);
|
||||
length = (size_t)file_size.QuadPart;
|
||||
}
|
||||
|
||||
if (length == 0) return;
|
||||
|
||||
DWORD protect = 0;
|
||||
DWORD access = 0;
|
||||
switch (flags) {
|
||||
case readonly:
|
||||
protect = PAGE_READONLY;
|
||||
access = FILE_MAP_READ;
|
||||
break;
|
||||
case readwrite:
|
||||
protect = PAGE_READWRITE;
|
||||
access = FILE_MAP_WRITE;
|
||||
break;
|
||||
case priv:
|
||||
protect = PAGE_WRITECOPY;
|
||||
access = FILE_MAP_COPY;
|
||||
break;
|
||||
}
|
||||
|
||||
mh = CreateFileMapping(fh, nullptr, protect, 0, 0, 0);
|
||||
if (mh == INVALID_HANDLE_VALUE)
|
||||
return set_or_throw_error(ec, "CreateFileMapping");
|
||||
|
||||
auto mh_close = make_unique_resource(mh, CloseHandle);
|
||||
|
||||
|
||||
ULARGE_INTEGER ll;
|
||||
ll.QuadPart = offset;
|
||||
|
||||
_data = MapViewOfFileEx(mh,
|
||||
access,
|
||||
ll.HighPart,
|
||||
ll.LowPart,
|
||||
length,
|
||||
nullptr);
|
||||
if (!_data)
|
||||
return set_or_throw_error(ec, "MapViewOfFileEx");
|
||||
|
||||
|
||||
_file_handle = fh_close.release();
|
||||
_map_handle = mh_close.release();
|
||||
_size = length;
|
||||
_flags = flags;
|
||||
}
|
||||
|
||||
void mapped_file_base::open(const std::string &p, mapmode flags, size_t length, size_t offset, std::error_code *ec) {
|
||||
open_common(p, flags, length, offset, ec);
|
||||
}
|
||||
|
||||
void mapped_file_base::open(const std::wstring &p, mapmode flags, size_t length, size_t offset, std::error_code *ec) {
|
||||
open_common(p, flags, length, offset, ec);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
template<class T>
|
||||
void mapped_file_base::create_common(const T& p, size_t length, std::error_code *ec) {
|
||||
|
||||
if (ec) ec->clear();
|
||||
|
||||
const size_t offset = 0;
|
||||
|
||||
HANDLE fh;
|
||||
HANDLE mh;
|
||||
LARGE_INTEGER file_size;
|
||||
|
||||
const DWORD protect = PAGE_READWRITE;
|
||||
const DWORD access = FILE_MAP_WRITE;
|
||||
|
||||
|
||||
if (is_open()) close();
|
||||
|
||||
fh = CreateFileX(p,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ,
|
||||
nullptr,
|
||||
CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
nullptr
|
||||
);
|
||||
if (fh == INVALID_HANDLE_VALUE)
|
||||
return set_or_throw_error(ec, "CreateFile");
|
||||
|
||||
auto fh_close = make_unique_resource(fh, CloseHandle);
|
||||
|
||||
if (length == 0) return;
|
||||
|
||||
file_size.QuadPart = length;
|
||||
if (!SetFilePointerEx(fh, file_size, nullptr, FILE_BEGIN))
|
||||
return set_or_throw_error(ec, "SetFilePointerEx");
|
||||
|
||||
if (!SetEndOfFile(fh))
|
||||
return set_or_throw_error(ec, "SetEndOfFile");
|
||||
|
||||
mh = CreateFileMapping(fh, nullptr, protect, 0, 0, 0);
|
||||
if (mh == INVALID_HANDLE_VALUE)
|
||||
return set_or_throw_error(ec, "CreateFileMapping");
|
||||
|
||||
auto mh_close = make_unique_resource(mh, CloseHandle);
|
||||
|
||||
ULARGE_INTEGER ll;
|
||||
ll.QuadPart = offset;
|
||||
|
||||
_data = MapViewOfFileEx(mh,
|
||||
access,
|
||||
ll.HighPart,
|
||||
ll.LowPart,
|
||||
length,
|
||||
nullptr);
|
||||
|
||||
if (!_data)
|
||||
return set_or_throw_error(ec, "MapViewOfFileEx");
|
||||
|
||||
_file_handle = fh_close.release();
|
||||
_map_handle = mh_close.release();
|
||||
|
||||
_size = length;
|
||||
_flags = readwrite;
|
||||
}
|
||||
|
||||
void mapped_file_base::create(const std::string &p, size_t length, std::error_code *ec) {
|
||||
create_common(p, length, ec);
|
||||
}
|
||||
void mapped_file_base::create(const std::wstring &p, size_t length, std::error_code *ec) {
|
||||
create_common(p, length, ec);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <cerrno>
|
||||
|
||||
namespace {
|
||||
|
||||
|
||||
void set_or_throw_error(std::error_code *ec, const char *what) {
|
||||
set_or_throw_error(ec, errno, what);
|
||||
}
|
||||
|
||||
void set_or_throw_error(std::error_code *ec, const std::string &what) {
|
||||
set_or_throw_error(ec, errno, what);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void mapped_file_base::close() {
|
||||
if (is_open()) {
|
||||
::munmap(_data, _size);
|
||||
::close(_fd);
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void mapped_file_base::open(const std::string& p, mapmode flags, size_t length, size_t offset, std::error_code *ec) {
|
||||
|
||||
if (ec) ec->clear();
|
||||
|
||||
int fd;
|
||||
|
||||
int oflags = 0;
|
||||
|
||||
if (is_open()) close();
|
||||
|
||||
switch (flags) {
|
||||
case readonly:
|
||||
oflags = O_RDONLY;
|
||||
break;
|
||||
default:
|
||||
oflags = O_RDWR;
|
||||
break;
|
||||
}
|
||||
|
||||
fd = ::open(p.c_str(), oflags);
|
||||
if (fd < 0) {
|
||||
return set_or_throw_error(ec, "open");
|
||||
}
|
||||
|
||||
auto close_fd = make_unique_resource(fd, ::close);
|
||||
|
||||
|
||||
if (length == -1) {
|
||||
struct stat st;
|
||||
|
||||
if (::fstat(fd, &st) < 0) {
|
||||
set_or_throw_error(ec, "stat");
|
||||
return;
|
||||
}
|
||||
length = st.st_size;
|
||||
}
|
||||
|
||||
if (length == 0) return;
|
||||
|
||||
_data = ::mmap(0, length,
|
||||
flags == readonly ? PROT_READ : PROT_READ | PROT_WRITE,
|
||||
flags == priv ? MAP_PRIVATE : MAP_SHARED,
|
||||
fd, offset);
|
||||
|
||||
if (_data == MAP_FAILED) {
|
||||
_data = nullptr;
|
||||
return set_or_throw_error(ec, "mmap");
|
||||
}
|
||||
|
||||
_fd = close_fd.release();
|
||||
_size = length;
|
||||
_flags = flags;
|
||||
}
|
||||
|
||||
void mapped_file_base::create(const std::string& p, size_t length, std::error_code *ec) {
|
||||
|
||||
if (ec) ec->clear();
|
||||
|
||||
int fd;
|
||||
const size_t offset = 0;
|
||||
|
||||
if (is_open()) close();
|
||||
|
||||
fd = ::open(p.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0666);
|
||||
if (fd < 0) {
|
||||
return set_or_throw_error(ec, "open");
|
||||
}
|
||||
|
||||
|
||||
auto close_fd = make_unique_resource(fd, ::close);
|
||||
|
||||
|
||||
if (length == 0) return;
|
||||
|
||||
if (::ftruncate(fd, length) < 0) {
|
||||
return set_or_throw_error(ec, "ftruncate");
|
||||
}
|
||||
|
||||
|
||||
_data = ::mmap(0, length,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED,
|
||||
fd, offset);
|
||||
|
||||
if (_data == MAP_FAILED) {
|
||||
_data = nullptr;
|
||||
return set_or_throw_error(ec, "mmap");
|
||||
}
|
||||
|
||||
_fd = close_fd.release();
|
||||
_size = length;
|
||||
_flags = readwrite;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
void mapped_file_base::reset() {
|
||||
_data = nullptr;
|
||||
_size = 0;
|
||||
_flags = readonly;
|
||||
#ifdef _WIN32
|
||||
_file_handle = nullptr;
|
||||
_map_handle = nullptr;
|
||||
#else
|
||||
_fd = -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void mapped_file_base::swap(mapped_file_base &rhs)
|
||||
{
|
||||
if (std::addressof(rhs) != this) {
|
||||
std::swap(_data, rhs._data);
|
||||
std::swap(_size, rhs._size);
|
||||
std::swap(_flags, rhs._flags);
|
||||
#ifdef _WIN32
|
||||
std::swap(_file_handle, rhs._file_handle);
|
||||
std::swap(_map_handle, rhs._map_handle);
|
||||
#else
|
||||
std::swap(_fd, rhs._fd);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
mapped_file::mapped_file(mapped_file &&rhs) : mapped_file() {
|
||||
swap(rhs);
|
||||
//rhs.reset();
|
||||
}
|
||||
|
||||
mapped_file& mapped_file::operator=(mapped_file &&rhs) {
|
||||
if (std::addressof(rhs) == this) return *this;
|
||||
|
||||
swap(rhs);
|
||||
rhs.close();
|
||||
//rhs.reset();
|
||||
return *this;
|
||||
}
|
||||
|
237
mapped_file.h
Normal file
237
mapped_file.h
Normal file
|
@ -0,0 +1,237 @@
|
|||
#ifndef __mapped_file_h__
|
||||
#define __mapped_file_h__
|
||||
|
||||
#include <cstddef>
|
||||
#include <system_error>
|
||||
#include <string>
|
||||
|
||||
class mapped_file_base {
|
||||
public:
|
||||
|
||||
|
||||
enum mapmode { readonly, readwrite, priv };
|
||||
enum createmode { truncate, exclusive };
|
||||
|
||||
void close();
|
||||
|
||||
bool is_open() const {
|
||||
return _data != nullptr;
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return _size;
|
||||
}
|
||||
|
||||
operator bool() const { return is_open(); }
|
||||
bool operator !() const { return !is_open(); }
|
||||
|
||||
~mapped_file_base() { close(); }
|
||||
|
||||
protected:
|
||||
|
||||
void swap(mapped_file_base &rhs);
|
||||
|
||||
void open(const std::string &p, mapmode flags, size_t length, size_t offset, std::error_code *ec);
|
||||
void create(const std::string &p, size_t new_size, std::error_code *ec); // always creates readwrite.
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
void open(const std::wstring &p, mapmode flags, size_t length, size_t offset, std::error_code *ec);
|
||||
void create(const std::wstring &p, size_t new_size, std::error_code *ec); // always creates readwrite.
|
||||
|
||||
template<class S>
|
||||
void open_common(const S &p, mapmode flags, size_t length, size_t offset, std::error_code *ec);
|
||||
|
||||
template<class S>
|
||||
void create_common(const S &p, size_t new_size, std::error_code *ec); // always creates readwrite.
|
||||
|
||||
#endif
|
||||
|
||||
void reset();
|
||||
|
||||
|
||||
size_t _size = 0;
|
||||
void *_data = nullptr;
|
||||
mapmode _flags = readonly;
|
||||
|
||||
#ifdef _WIN32
|
||||
void *_file_handle = nullptr;
|
||||
void *_map_handle = nullptr;
|
||||
#else
|
||||
int _fd = -1;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
||||
class mapped_file : public mapped_file_base {
|
||||
|
||||
typedef mapped_file_base base;
|
||||
|
||||
public:
|
||||
|
||||
typedef unsigned char value_type;
|
||||
|
||||
typedef value_type *iterator;
|
||||
typedef const value_type *const_iterator;
|
||||
|
||||
typedef value_type &reference ;
|
||||
typedef const value_type &const_reference;
|
||||
|
||||
|
||||
mapped_file() = default;
|
||||
mapped_file(mapped_file &&);
|
||||
mapped_file(const mapped_file &) = delete;
|
||||
|
||||
|
||||
mapped_file(const std::string &p, mapmode flags = readonly, size_t length = -1, size_t offset = 0) {
|
||||
open(p, flags, length, offset);
|
||||
}
|
||||
|
||||
mapped_file(const std::string &p, std::error_code &ec) noexcept {
|
||||
open(p, readonly, -1, 0, ec);
|
||||
}
|
||||
mapped_file(const std::string &p, mapmode flags, std::error_code &ec) noexcept {
|
||||
open(p, flags, -1, 0, ec);
|
||||
}
|
||||
|
||||
mapped_file(const std::string &p, mapmode flags, size_t length, std::error_code &ec) noexcept {
|
||||
open(p, flags, length, 0, ec);
|
||||
}
|
||||
|
||||
mapped_file(const std::string &p, mapmode flags, size_t length, size_t offset, std::error_code &ec) noexcept {
|
||||
open(p, flags, length, offset, ec);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
mapped_file(const std::wstring &p, mapmode flags = readonly, size_t length = -1, size_t offset = 0) {
|
||||
open(p, flags, length, offset);
|
||||
}
|
||||
|
||||
mapped_file(const std::wstring &p, std::error_code &ec) noexcept {
|
||||
open(p, readonly, -1, 0, ec);
|
||||
}
|
||||
mapped_file(const std::wstring &p, mapmode flags, std::error_code &ec) noexcept {
|
||||
open(p, flags, -1, 0, ec);
|
||||
}
|
||||
|
||||
mapped_file(const std::wstring &p, mapmode flags, size_t length, std::error_code &ec) noexcept {
|
||||
open(p, flags, length, 0, ec);
|
||||
}
|
||||
|
||||
mapped_file(const std::wstring &p, mapmode flags, size_t length, size_t offset, std::error_code &ec) noexcept {
|
||||
open(p, flags, length, offset, ec);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
mapped_file &operator=(mapped_file &&);
|
||||
mapped_file &operator=(const mapped_file &) = delete;
|
||||
|
||||
|
||||
void open(const std::string &p, mapmode flags, size_t length = -1, size_t offset = 0) {
|
||||
base::open(p, flags, length, offset, nullptr);
|
||||
}
|
||||
void open(const std::string &p, std::error_code &ec) noexcept {
|
||||
base::open(p, readonly, -1, 0, &ec);
|
||||
}
|
||||
void open(const std::string &p, mapmode flags, std::error_code &ec) noexcept {
|
||||
base::open(p, flags, -1, 0, &ec);
|
||||
}
|
||||
void open(const std::string &p, mapmode flags, size_t length, std::error_code &ec) noexcept {
|
||||
base::open(p, flags, length, 0, &ec);
|
||||
}
|
||||
void open(const std::string &p, mapmode flags, size_t length, size_t offset, std::error_code &ec) noexcept {
|
||||
base::open(p, flags, length, offset, &ec);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
void open(const std::wstring &p, mapmode flags, size_t length = -1, size_t offset = 0) {
|
||||
base::open(p, flags, length, offset, nullptr);
|
||||
}
|
||||
void open(const std::wstring &p, std::error_code &ec) noexcept {
|
||||
base::open(p, readonly, -1, 0, &ec);
|
||||
}
|
||||
void open(const std::wstring &p, mapmode flags, std::error_code &ec) noexcept {
|
||||
base::open(p, flags, -1, 0, &ec);
|
||||
}
|
||||
void open(const std::wstring &p, mapmode flags, size_t length, std::error_code &ec) noexcept {
|
||||
base::open(p, flags, length, 0, &ec);
|
||||
}
|
||||
void open(const std::wstring &p, mapmode flags, size_t length, size_t offset, std::error_code &ec) noexcept {
|
||||
base::open(p, flags, length, offset, &ec);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void create(const std::string &p, size_t size) {
|
||||
base::create(p, size, nullptr);
|
||||
}
|
||||
void create(const std::string &p, size_t size, std::error_code &ec) noexcept {
|
||||
base::create(p, size, &ec);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
void create(const std::wstring &p, size_t size) {
|
||||
base::create(p, size, nullptr);
|
||||
}
|
||||
void create(const std::wstring &p, size_t size, std::error_code &ec) noexcept {
|
||||
base::create(p, size, &ec);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
const value_type *data() const {
|
||||
return (const value_type *)_data;
|
||||
}
|
||||
|
||||
value_type *data() {
|
||||
return (value_type *)_data;
|
||||
}
|
||||
|
||||
const_iterator cbegin() const {
|
||||
return data();
|
||||
}
|
||||
|
||||
const_iterator cend() const {
|
||||
return data() + size();
|
||||
}
|
||||
|
||||
const_iterator begin() const {
|
||||
return cbegin();
|
||||
}
|
||||
|
||||
const_iterator end() const {
|
||||
return cend();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
iterator begin() {
|
||||
return (iterator)_data;
|
||||
}
|
||||
|
||||
iterator end() {
|
||||
return (iterator)_data + size();
|
||||
}
|
||||
|
||||
mapmode flags() const {
|
||||
return _flags;
|
||||
}
|
||||
|
||||
void swap(mapped_file &rhs) {
|
||||
base::swap(rhs);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
namespace std {
|
||||
template<class T>
|
||||
void swap(mapped_file &a, mapped_file &b) {
|
||||
a.swap(b);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
504
omf.cpp
Normal file
504
omf.cpp
Normal file
|
@ -0,0 +1,504 @@
|
|||
#include "omf.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <optional>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <err.h>
|
||||
#include <sysexits.h>
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0
|
||||
#endif
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct omf_header {
|
||||
uint32_t bytecount = 0;
|
||||
uint32_t reserved_space = 0;
|
||||
uint32_t length = 0;
|
||||
uint8_t unused1 = 0;
|
||||
uint8_t lablen = 0;
|
||||
uint8_t numlen = 4;
|
||||
uint8_t version = 2;
|
||||
uint32_t banksize = 0;
|
||||
uint16_t kind = 0;
|
||||
uint16_t unused2 = 0;
|
||||
uint32_t org = 0;
|
||||
uint32_t alignment = 0;
|
||||
uint8_t numsex = 0;
|
||||
uint8_t unused3 = 0;
|
||||
uint16_t segnum = 0;
|
||||
uint32_t entry = 0;
|
||||
uint16_t dispname = 0;
|
||||
uint16_t dispdata = 0;
|
||||
};
|
||||
|
||||
struct omf_express_header {
|
||||
uint32_t lconst_mark;
|
||||
uint32_t lconst_size;
|
||||
uint32_t reloc_mark;
|
||||
uint32_t reloc_size;
|
||||
uint8_t unused1 = 0;
|
||||
uint8_t lablen = 0;
|
||||
uint8_t numlen = 4;
|
||||
uint8_t version = 2;
|
||||
uint32_t banksize = 0;
|
||||
uint16_t kind = 0;
|
||||
uint16_t unused2 = 0;
|
||||
uint32_t org = 0;
|
||||
uint32_t alignment = 0;
|
||||
uint8_t numsex = 0;
|
||||
uint8_t unused3 = 0;
|
||||
uint16_t segnum = 0;
|
||||
uint32_t entry = 0;
|
||||
uint16_t dispname = 0;
|
||||
uint16_t dispdata = 0;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
void push(std::vector<uint8_t> &v, uint8_t x) {
|
||||
v.push_back(x);
|
||||
}
|
||||
|
||||
void push(std::vector<uint8_t> &v, uint16_t x) {
|
||||
v.push_back(x & 0xff);
|
||||
x >>= 8;
|
||||
v.push_back(x & 0xff);
|
||||
}
|
||||
|
||||
void push(std::vector<uint8_t> &v, uint32_t x) {
|
||||
v.push_back(x & 0xff);
|
||||
x >>= 8;
|
||||
v.push_back(x & 0xff);
|
||||
x >>= 8;
|
||||
v.push_back(x & 0xff);
|
||||
x >>= 8;
|
||||
v.push_back(x & 0xff);
|
||||
}
|
||||
|
||||
void push(std::vector<uint8_t> &v, const std::string &s) {
|
||||
uint8_t count = std::min((int)s.size(), 255);
|
||||
push(v, count);
|
||||
v.insert(v.end(), s.begin(), s.end());
|
||||
}
|
||||
|
||||
class super_helper {
|
||||
|
||||
std::vector<uint8_t> _data;
|
||||
uint32_t _page = 0;
|
||||
int _count = 0;
|
||||
|
||||
public:
|
||||
|
||||
super_helper() = default;
|
||||
|
||||
|
||||
void append(uint32_t pc) {
|
||||
unsigned offset = pc & 0xff;
|
||||
unsigned page = pc >> 8;
|
||||
assert(page >= _page);
|
||||
|
||||
if (page != _page) {
|
||||
unsigned skip = page - _page;
|
||||
if (skip > 1) {
|
||||
|
||||
while (skip >= 0x80) {
|
||||
_data.push_back(0xff);
|
||||
skip -= 0x7f;
|
||||
}
|
||||
if (skip)
|
||||
_data.push_back(0x80 | skip);
|
||||
}
|
||||
_page = page;
|
||||
_count = 0;
|
||||
}
|
||||
|
||||
if (!_count) {
|
||||
_data.push_back(0); // count-1 place holder.
|
||||
} else {
|
||||
_data[_data.size() - _count - 1] = _count; // count is count - 1 at this point,
|
||||
}
|
||||
|
||||
_data.push_back(offset);
|
||||
++_count;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
_data.clear();
|
||||
_page = 0;
|
||||
_count = 0;
|
||||
}
|
||||
|
||||
const std::vector<uint8_t> &data() {
|
||||
return _data;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
enum {
|
||||
SUPER_RELOC2,
|
||||
SUPER_RELOC3,
|
||||
SUPER_INTERSEG1,
|
||||
SUPER_INTERSEG2,
|
||||
SUPER_INTERSEG3,
|
||||
SUPER_INTERSEG4,
|
||||
SUPER_INTERSEG5,
|
||||
SUPER_INTERSEG6,
|
||||
SUPER_INTERSEG7,
|
||||
SUPER_INTERSEG8,
|
||||
SUPER_INTERSEG9,
|
||||
SUPER_INTERSEG10,
|
||||
SUPER_INTERSEG11,
|
||||
SUPER_INTERSEG12,
|
||||
SUPER_INTERSEG13,
|
||||
SUPER_INTERSEG14,
|
||||
SUPER_INTERSEG15,
|
||||
SUPER_INTERSEG16,
|
||||
SUPER_INTERSEG17,
|
||||
SUPER_INTERSEG18,
|
||||
SUPER_INTERSEG19,
|
||||
SUPER_INTERSEG20,
|
||||
SUPER_INTERSEG21,
|
||||
SUPER_INTERSEG22,
|
||||
SUPER_INTERSEG23,
|
||||
SUPER_INTERSEG24,
|
||||
SUPER_INTERSEG25,
|
||||
SUPER_INTERSEG26,
|
||||
SUPER_INTERSEG27,
|
||||
SUPER_INTERSEG28,
|
||||
SUPER_INTERSEG29,
|
||||
SUPER_INTERSEG30,
|
||||
SUPER_INTERSEG31,
|
||||
SUPER_INTERSEG32,
|
||||
SUPER_INTERSEG33,
|
||||
SUPER_INTERSEG34,
|
||||
SUPER_INTERSEG35,
|
||||
SUPER_INTERSEG36,
|
||||
};
|
||||
|
||||
uint32_t add_relocs(std::vector<uint8_t> &data, size_t data_offset, omf::segment &seg, bool compress) {
|
||||
|
||||
std::array< std::optional<super_helper>, 38 > ss;
|
||||
|
||||
|
||||
uint32_t reloc_size = 0;
|
||||
|
||||
for (auto &r : seg.relocs) {
|
||||
|
||||
if (r.can_compress()) {
|
||||
|
||||
if (compress) {
|
||||
if (r.shift == 0 && r.size == 2) {
|
||||
constexpr int n = SUPER_RELOC2;
|
||||
|
||||
auto &sr = ss[n];
|
||||
if (!sr) sr.emplace();
|
||||
|
||||
uint32_t value = r.value;
|
||||
sr->append(r.offset);
|
||||
for (int i = 0; i < 2; ++i, value >>= 8)
|
||||
data[data_offset + r.offset + i] = value;
|
||||
continue;
|
||||
}
|
||||
|
||||
// sreloc 3 is for 3 bytes. however 4 bytes is also ok since
|
||||
// it's 24-bit address space.
|
||||
if (r.shift == 0 && (r.size == 2 || r.size == 3))
|
||||
{
|
||||
constexpr int n = SUPER_RELOC3;
|
||||
|
||||
auto &sr = ss[n];
|
||||
if (!sr) sr.emplace();
|
||||
|
||||
uint32_t value = r.value;
|
||||
sr->append(r.offset);
|
||||
for (int i = 0; i < 3; ++i, value >>= 8)
|
||||
data[data_offset + r.offset + i] = value;
|
||||
continue;
|
||||
}
|
||||
|
||||
// if size == 2 && shift == -16, -> SUPER INTERSEG
|
||||
if (seg.segnum <= 12 && r.shift == 0xf0 && r.size == 2) {
|
||||
|
||||
int n = SUPER_INTERSEG24 + seg.segnum;
|
||||
auto &sr = ss[n];
|
||||
if (!sr) sr.emplace();
|
||||
|
||||
uint32_t value = r.value;
|
||||
sr->append(r.offset);
|
||||
for (int i = 0; i < 2; ++i, value >>= 8)
|
||||
data[data_offset + r.offset + i] = value;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
push(data, (uint8_t)omf::cRELOC);
|
||||
push(data, (uint8_t)r.size);
|
||||
push(data, (uint8_t)r.shift);
|
||||
push(data, (uint16_t)r.offset);
|
||||
push(data, (uint16_t)r.value);
|
||||
reloc_size += 7;
|
||||
} else {
|
||||
push(data, (uint8_t)omf::RELOC);
|
||||
push(data, (uint8_t)r.size);
|
||||
push(data, (uint8_t)r.shift);
|
||||
push(data, (uint32_t)r.offset);
|
||||
push(data, (uint32_t)r.value);
|
||||
reloc_size += 11;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &r : seg.intersegs) {
|
||||
if (r.can_compress()) {
|
||||
|
||||
if (compress) {
|
||||
|
||||
if (r.shift == 0 && r.size == 3) {
|
||||
constexpr int n = SUPER_INTERSEG1;
|
||||
auto &sr = ss[n];
|
||||
if (!sr) sr.emplace();
|
||||
|
||||
uint32_t value = r.segment_offset;
|
||||
data[data_offset + r.offset + 0] = value; value >>= 8;
|
||||
data[data_offset + r.offset + 1] = value; value >>= 8;
|
||||
data[data_offset + r.offset + 2] = r.segment;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (r.shift == 0 && r.size == 2 && r.segment <= 12) {
|
||||
|
||||
int n = SUPER_INTERSEG12 + r.segment;
|
||||
auto &sr = ss[n];
|
||||
if (!sr) sr.emplace();
|
||||
|
||||
uint32_t value = r.segment_offset;
|
||||
sr->append(r.offset);
|
||||
for (int i = 0; i < 2; ++i, value >>= 8)
|
||||
data[data_offset + r.offset + i] = value;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (r.shift == 0xf0 && r.size == 2 && r.segment <= 12) {
|
||||
|
||||
int n = SUPER_INTERSEG24 + r.segment;
|
||||
auto &sr = ss[n];
|
||||
if (!sr) sr.emplace();
|
||||
|
||||
uint32_t value = r.segment_offset;
|
||||
sr->append(r.offset);
|
||||
for (int i = 0; i < 2; ++i, value >>= 8)
|
||||
data[data_offset + r.offset + i] = value;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
push(data, (uint8_t)omf::cINTERSEG);
|
||||
push(data, (uint8_t)r.size);
|
||||
push(data, (uint8_t)r.shift);
|
||||
push(data, (uint16_t)r.offset);
|
||||
push(data, (uint8_t)r.segment);
|
||||
push(data, (uint16_t)r.segment_offset);
|
||||
reloc_size += 8;
|
||||
} else {
|
||||
push(data, (uint8_t)omf::INTERSEG);
|
||||
push(data, (uint8_t)r.size);
|
||||
push(data, (uint8_t)r.shift);
|
||||
push(data, (uint32_t)r.offset);
|
||||
push(data, (uint16_t)r.file);
|
||||
push(data, (uint16_t)r.segment);
|
||||
push(data, (uint32_t)r.segment_offset);
|
||||
reloc_size += 15;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (int i = 0; i < ss.size(); ++i) {
|
||||
auto &s = ss[i];
|
||||
if (!s) continue;
|
||||
|
||||
auto tmp = s->data();
|
||||
if (tmp.empty()) continue;
|
||||
|
||||
reloc_size += tmp.size() + 6;
|
||||
data.push_back(omf::SUPER);
|
||||
push(data, ((uint32_t)tmp.size() + 1));
|
||||
data.push_back(i);
|
||||
|
||||
data.insert(data.end(), tmp.begin(), tmp.end());
|
||||
}
|
||||
|
||||
return reloc_size;
|
||||
}
|
||||
|
||||
void save_omf(const std::string &path, std::vector<omf::segment> &segments, bool compress, bool expressload) {
|
||||
|
||||
// expressload doesn't support links to other files.
|
||||
// fortunately, we don't either.
|
||||
|
||||
std::vector<uint8_t> expr_headers;
|
||||
std::vector<unsigned> expr_offsets;
|
||||
|
||||
int fd;
|
||||
fd = open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
|
||||
if (fd < 0) {
|
||||
err(EX_CANTCREAT, "Unable to open %s", path.c_str());
|
||||
}
|
||||
|
||||
|
||||
uint32_t offset = 0;
|
||||
if (expressload) {
|
||||
for (auto &s : segments) {
|
||||
s.segnum++;
|
||||
for (auto &r : s.intersegs) r.segment++;
|
||||
}
|
||||
|
||||
// calculate express load segment size.
|
||||
// sizeof includes the trailing 0, so no need to add in byte size.
|
||||
offset = sizeof(omf_header) + 10 + sizeof("~ExpressLoad");
|
||||
|
||||
offset += 6; // lconst + end
|
||||
offset += 6; // header.
|
||||
for (auto &s : segments) {
|
||||
offset += 8 + 2;
|
||||
offset += sizeof(omf_express_header) + 10;
|
||||
offset += s.segname.length() + 1;
|
||||
}
|
||||
|
||||
lseek(fd, offset, SEEK_SET);
|
||||
}
|
||||
|
||||
|
||||
for (auto &s : segments) {
|
||||
omf_header h;
|
||||
h.length = s.data.size();
|
||||
h.kind = s.kind;
|
||||
h.banksize = s.data.size() > 0xffff ? 0x0000 : 0x010000;
|
||||
h.segnum = s.segnum;
|
||||
|
||||
std::vector<uint8_t> data;
|
||||
|
||||
// push segname and load name onto data.
|
||||
data.insert(data.end(), 10, ' ');
|
||||
push(data, s.segname);
|
||||
|
||||
h.dispname = sizeof(omf_header);
|
||||
h.dispdata = sizeof(omf_header) + data.size();
|
||||
|
||||
|
||||
|
||||
uint32_t lconst_offset = offset + sizeof(omf_header) + data.size() + 5;
|
||||
uint32_t lconst_size = h.length;
|
||||
|
||||
//lconst record
|
||||
push(data, (uint8_t)omf::LCONST);
|
||||
push(data, (uint32_t)h.length);
|
||||
|
||||
size_t data_offset = data.size();
|
||||
|
||||
data.insert(data.end(), s.data.begin(), s.data.end());
|
||||
|
||||
|
||||
uint32_t reloc_offset = offset + sizeof(omf_header) + data.size();
|
||||
uint32_t reloc_size = 0;
|
||||
|
||||
reloc_size = add_relocs(data, data_offset, s, compress);
|
||||
|
||||
// end-of-record
|
||||
push(data, (uint8_t)omf::END);
|
||||
|
||||
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) {
|
||||
|
||||
expr_offsets.emplace_back(expr_headers.size());
|
||||
|
||||
if (lconst_size == 0) lconst_offset = 0;
|
||||
if (reloc_size == 0) reloc_offset = 0;
|
||||
|
||||
|
||||
push(expr_headers, (uint32_t)lconst_offset);
|
||||
push(expr_headers, (uint32_t)lconst_size);
|
||||
push(expr_headers, (uint32_t)reloc_offset);
|
||||
push(expr_headers, (uint32_t)reloc_size);
|
||||
|
||||
push(expr_headers, h.unused1);
|
||||
push(expr_headers, h.lablen);
|
||||
push(expr_headers, h.numlen);
|
||||
push(expr_headers, h.version);
|
||||
push(expr_headers, h.banksize);
|
||||
push(expr_headers, h.kind);
|
||||
push(expr_headers, h.unused2);
|
||||
push(expr_headers, h.org);
|
||||
push(expr_headers, h.alignment);
|
||||
push(expr_headers, h.numsex);
|
||||
push(expr_headers, h.unused3);
|
||||
push(expr_headers, h.segnum);
|
||||
push(expr_headers, h.entry);
|
||||
push(expr_headers, (uint16_t)(h.dispname-4));
|
||||
push(expr_headers, h.dispdata);
|
||||
|
||||
expr_headers.insert(expr_headers.end(), 10, ' ');
|
||||
push(expr_headers, s.segname);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (expressload) {
|
||||
omf_header h;
|
||||
h.segnum = 1;
|
||||
h.banksize = 0x00010000;
|
||||
h.kind = 0x8001;
|
||||
h.dispname = 0x2c;
|
||||
h.dispdata = 0x43;
|
||||
|
||||
unsigned fudge = 10 * segments.size();
|
||||
|
||||
h.length = 6 + expr_headers.size() + fudge;
|
||||
|
||||
std::vector<uint8_t> data;
|
||||
data.insert(data.begin(), 10, ' ');
|
||||
push(data, std::string("~ExpressLoad"));
|
||||
push(data, (uint8_t)0xf2); // lconst.
|
||||
push(data, (uint32_t)h.length);
|
||||
|
||||
push(data, (uint32_t)0); // reserved
|
||||
push(data, (uint16_t)(segments.size() - 1)); // seg count - 1
|
||||
|
||||
|
||||
for (auto &offset : expr_offsets) {
|
||||
push(data, (uint16_t)(fudge + offset));
|
||||
push(data, (uint16_t)0);
|
||||
push(data, (uint32_t)0);
|
||||
}
|
||||
|
||||
for (auto &s : segments) {
|
||||
push(data, (uint16_t)s.segnum);
|
||||
}
|
||||
|
||||
data.insert(data.end(), expr_headers.begin(), expr_headers.end());
|
||||
push(data, (uint8_t)0); // end.
|
||||
|
||||
h.bytecount = data.size() + sizeof(omf_header);
|
||||
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
write(fd, &h, sizeof(h));
|
||||
write(fd, data.data(), data.size());
|
||||
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
79
omf.h
Normal file
79
omf.h
Normal file
|
@ -0,0 +1,79 @@
|
|||
#ifndef __omf_h__
|
||||
#define __omf_h__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace omf {
|
||||
|
||||
enum opcode : uint8_t {
|
||||
END = 0x00,
|
||||
// 0x01-0xdf CONST
|
||||
ALIGN = 0xe0,
|
||||
ORG = 0xe1,
|
||||
RELOC = 0xe2,
|
||||
INTERSEG = 0xe3,
|
||||
USING = 0xe4,
|
||||
STRONG = 0xe5,
|
||||
GLOBAL = 0xe6,
|
||||
GEQU = 0xe7,
|
||||
MEM = 0xe8,
|
||||
EXPR = 0xeb,
|
||||
ZEXPR = 0xec,
|
||||
BEXPR = 0xed,
|
||||
RELEXPR = 0xee,
|
||||
LOCAL = 0xef,
|
||||
EQU = 0xf0,
|
||||
DS = 0xf1,
|
||||
LCONST = 0xf2,
|
||||
LEXPR = 0xf3,
|
||||
ENTRY = 0xf4,
|
||||
cRELOC = 0xf5,
|
||||
cINTERSEG = 0xf6,
|
||||
SUPER = 0xf7,
|
||||
};
|
||||
|
||||
struct reloc {
|
||||
uint8_t size = 0;
|
||||
uint8_t shift = 0;
|
||||
uint32_t offset = 0;
|
||||
uint32_t value = 0;
|
||||
|
||||
constexpr bool can_compress() const {
|
||||
return offset <= 0xffff && value <= 0xffff;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct interseg {
|
||||
|
||||
uint8_t size = 0;
|
||||
uint8_t shift = 0;
|
||||
uint32_t offset = 0;
|
||||
uint16_t file = 1;
|
||||
uint16_t segment = 0;
|
||||
uint32_t segment_offset = 0;
|
||||
|
||||
constexpr bool can_compress() const {
|
||||
return file == 1 && segment <= 255 && offset <= 0xffff && segment_offset <= 0xffff;
|
||||
}
|
||||
};
|
||||
|
||||
struct segment {
|
||||
|
||||
uint16_t segnum = 0;
|
||||
uint16_t kind = 0;
|
||||
|
||||
std::string loadname;
|
||||
std::string segname;
|
||||
|
||||
std::vector<uint8_t> data;
|
||||
std::vector<interseg> intersegs;
|
||||
std::vector<reloc> relocs;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
40
ops.h
Normal file
40
ops.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
x(LNK)
|
||||
x(KND)
|
||||
x(ORG)
|
||||
x(ADR)
|
||||
x(TYP)
|
||||
x(END)
|
||||
x(PUT)
|
||||
x(ASM)
|
||||
x(OVR)
|
||||
x(SAV)
|
||||
x(DS)
|
||||
x(VER)
|
||||
x(ALI)
|
||||
x(LKV)
|
||||
x(DAT)
|
||||
x(LIB)
|
||||
x(ENT)
|
||||
x(EXT)
|
||||
x(NOL)
|
||||
x(FAS)
|
||||
x(POS)
|
||||
x(LEN)
|
||||
x(IF)
|
||||
x(DO)
|
||||
x(ELS)
|
||||
x(FIN)
|
||||
x(EQU)
|
||||
x(GEQ)
|
||||
x(KBD)
|
||||
x(RES)
|
||||
x(RID)
|
||||
x(RTY)
|
||||
x(RAT)
|
||||
x(FIL)
|
||||
x(AUX)
|
||||
x(CMD)
|
||||
x(ZIP)
|
||||
x(IMP)
|
||||
x(PFX)
|
||||
|
25
rel.h
Normal file
25
rel.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
#ifndef REL_H
|
||||
#define REL_H
|
||||
|
||||
enum {
|
||||
SYMBOL_ABSOLUTE = 0x20,
|
||||
SYMBOL_ENTRY = 0x40,
|
||||
SYMBOL_EXTERNAL = 0x80,
|
||||
};
|
||||
|
||||
enum {
|
||||
FLAG_EXTERNAL = 0x10,
|
||||
FLAG_3_BYTE = 0x20,
|
||||
FLAG_2_BYTE = 0x80,
|
||||
FLAG_SHIFT = 0xff,
|
||||
};
|
||||
|
||||
enum {
|
||||
SHIFT_16_1 = 0xd0,
|
||||
SHIFT_8_1 = 0xd3,
|
||||
SHIFT_8_2 = 0xd1,
|
||||
|
||||
SHIFT_EXTERNAL = 0x04,
|
||||
};
|
||||
|
||||
#endif
|
627
script.re2c
Normal file
627
script.re2c
Normal file
|
@ -0,0 +1,627 @@
|
|||
/* link script support */
|
||||
|
||||
/*
|
||||
|
||||
label opcode operand
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <cctype>
|
||||
#include <cstdio>
|
||||
#include <cstdint>
|
||||
|
||||
#include <err.h>
|
||||
|
||||
|
||||
/*!re2c
|
||||
re2c:define:YYCTYPE = char;
|
||||
re2c:yyfill:enable = 0;
|
||||
|
||||
// :-~ includes ; which interferes with comments.
|
||||
ident = [:<-~][0-~]*;
|
||||
ws = [ \t];
|
||||
eof = "\x00";
|
||||
*/
|
||||
|
||||
enum {
|
||||
CMD_NONE = 0,
|
||||
#define x(op) CMD_##op,
|
||||
#include "ops.h"
|
||||
#undef x
|
||||
CMD_EQ
|
||||
};
|
||||
|
||||
static std::unordered_map<std::string, int> commands = {
|
||||
#define x(op) { #op, CMD_##op },
|
||||
|
||||
#include "ops.h"
|
||||
#undef x
|
||||
|
||||
/* aliases */
|
||||
{ "AUX", CMD_ADR },
|
||||
{ "REZ", CMD_RES },
|
||||
{ "LIN", CMD_LNK },
|
||||
{ "KIN", CMD_KND },
|
||||
{ "=", CMD_EQ }
|
||||
};
|
||||
|
||||
|
||||
static std::unordered_map<std::string, int> types = {
|
||||
|
||||
{ "NON", 0x00 },
|
||||
{ "BAD", 0x01 },
|
||||
{ "BIN", 0x06 },
|
||||
{ "TXT", 0x04 },
|
||||
{ "DIR", 0x0f },
|
||||
{ "ADB", 0x19 },
|
||||
{ "AWP", 0x1a },
|
||||
{ "ASP", 0x1b },
|
||||
{ "GSB", 0xab },
|
||||
{ "TDF", 0xac },
|
||||
{ "BDF", 0xad },
|
||||
{ "SRC", 0xb0 },
|
||||
{ "OBJ", 0xb1 },
|
||||
{ "LIB", 0xb2 },
|
||||
{ "S16", 0xb3 },
|
||||
{ "RTL", 0xb4 },
|
||||
{ "EXE", 0xb5 },
|
||||
{ "PIF", 0xb6 },
|
||||
{ "TIF", 0xb7 },
|
||||
{ "NDA", 0xb8 },
|
||||
{ "CDA", 0xb9 },
|
||||
{ "TOL", 0xba },
|
||||
{ "DRV", 0xbb },
|
||||
{ "DOC", 0xbf },
|
||||
{ "PNT", 0xc0 },
|
||||
{ "PIC", 0xc1 },
|
||||
{ "FON", 0xcb },
|
||||
{ "PAS", 0xef },
|
||||
{ "CMD", 0xf0 },
|
||||
{ "LNK", 0xf8 },
|
||||
{ "BAS", 0xfc },
|
||||
{ "VAR", 0xfd },
|
||||
{ "REL", 0xfe },
|
||||
{ "SYS", 0xff },
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
static uint32_t number_operand(const char *YYCURSOR, bool required = true) {
|
||||
|
||||
char *iter = YYCURSOR;
|
||||
uint32_t rv = 0;
|
||||
/*!re2c
|
||||
* { throw std::invalid_argument("bad operand"); }
|
||||
[;*] | eof {
|
||||
if (!required) return rv;
|
||||
throw std::invalid_argument("missing operand");
|
||||
}
|
||||
'%' [01]+ {
|
||||
++iter;
|
||||
for(;iter < YYCURSOR; ++iter) {
|
||||
rv <<= 1;
|
||||
rv |= *iter - '0';
|
||||
}
|
||||
goto exit;
|
||||
}
|
||||
|
||||
'$' [A-Fa-f0-9]+ {
|
||||
++iter;
|
||||
for(;iter < YYCURSOR; ++iter) {
|
||||
char c = *iter | 0x20;
|
||||
rv <<= 4;
|
||||
if (c <= '9') rv |= c - '0';
|
||||
else rv |= c - 'a' + 10;
|
||||
}
|
||||
goto exit;
|
||||
}
|
||||
|
||||
[0-9]+ {
|
||||
for(;iter < YYCURSOR; ++iter) {
|
||||
rv *= 10;
|
||||
rv += *iter - '0';
|
||||
}
|
||||
goto exit;
|
||||
|
||||
}
|
||||
|
||||
ident {
|
||||
std::string s(iter, YYCURSOR);
|
||||
//look up symbol, verify it's an absolute value, etc
|
||||
}
|
||||
*/
|
||||
exit:
|
||||
char c = *YYCURSOR;
|
||||
if (isspace(c) || c == 0) return rv;
|
||||
|
||||
throw std::invalid_argument("bad operand");
|
||||
}
|
||||
|
||||
static uint32_t type_operand(const char *YYCURSOR, bool required = true) {
|
||||
|
||||
char *iter = YYCURSOR;
|
||||
uint32_t rv = 0;
|
||||
/*!re2c
|
||||
* { throw std::invalid_argument("bad operand"); }
|
||||
|
||||
[;*] | eof {
|
||||
if (!required) return rv;
|
||||
throw std::invalid_argument("missing operand");
|
||||
}
|
||||
|
||||
'%' [01]+ {
|
||||
++iter;
|
||||
for(;iter < YYCURSOR; ++iter) {
|
||||
rv <<= 1;
|
||||
rv |= *iter - '0';
|
||||
}
|
||||
goto exit;
|
||||
}
|
||||
|
||||
'$' [A-Fa-f0-9]+ {
|
||||
++iter;
|
||||
for(;iter < YYCURSOR; ++iter) {
|
||||
char c = *iter | 0x20;
|
||||
rv <<= 4;
|
||||
if (c <= '9') rv |= c - '0';
|
||||
else rv |= c - 'a' + 10;
|
||||
}
|
||||
goto exit;
|
||||
}
|
||||
|
||||
[0-9]+ {
|
||||
for(;iter < YYCURSOR; ++iter) {
|
||||
rv *= 10;
|
||||
rv += *iter - '0';
|
||||
}
|
||||
goto exit;
|
||||
|
||||
}
|
||||
|
||||
[A-Za-z][A-Za-z0-9]{2} {
|
||||
std::string s(iter, YYCURSOR);
|
||||
for(char &c : s) c = std::toupper(c);
|
||||
auto iter = types.find(s);
|
||||
if (iter == types.end) {
|
||||
throw std::invalid_argument("bad operand");
|
||||
}
|
||||
rv = *iter;
|
||||
}
|
||||
*/
|
||||
exit:
|
||||
char c = *YYCURSOR;
|
||||
if (isspace(c) || c == 0) return rv;
|
||||
|
||||
throw std::invalid_argument("bad operand");
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int x_number_operand(const char *YYCURSOR) {
|
||||
char *iter = YYCURSOR;
|
||||
uint32_t rv = 0;
|
||||
/*!re2c
|
||||
* { throw std::invalid_argument("bad operand"); }
|
||||
|
||||
'%' [01]+ {
|
||||
++iter;
|
||||
for(;iter < YYCURSOR; ++iter) {
|
||||
rv <<= 1;
|
||||
rv |= *iter - '0';
|
||||
}
|
||||
goto exit;
|
||||
}
|
||||
|
||||
'$' [A-Fa-f0-9]+ {
|
||||
++iter;
|
||||
for(;iter < YYCURSOR; ++iter) {
|
||||
char c = *iter | 0x20;
|
||||
rv <<= 4;
|
||||
if (c <= '9') rv |= c - '0';
|
||||
else rv |= c - 'a' + 10;
|
||||
}
|
||||
goto exit;
|
||||
}
|
||||
|
||||
[0-9]+ {
|
||||
for(;iter < YYCURSOR; ++iter) {
|
||||
rv *= 10;
|
||||
rv += *iter - '0';
|
||||
}
|
||||
goto exit;
|
||||
|
||||
}
|
||||
*/
|
||||
exit:
|
||||
char c = *YYCURSOR;
|
||||
if (isspace(c) || c == 0) return rv;
|
||||
|
||||
throw std::invalid_argument("bad operand");
|
||||
}
|
||||
|
||||
static std::string x_label_operand(const char *YYCURSOR) {
|
||||
char *iter = YYCURSOR;
|
||||
std::string rv;
|
||||
/*!re2c
|
||||
* { throw std::invalid_argument("bad operand"); }
|
||||
|
||||
ident {
|
||||
std::string s(iter, YYCURSOR);
|
||||
//look up symbol, verify it's an absolute value, etc
|
||||
}
|
||||
*/
|
||||
exit:
|
||||
char c = *YYCURSOR;
|
||||
if (isspace(c) || c == 0) return rv;
|
||||
throw std::invalid_argument("bad operand");
|
||||
}
|
||||
|
||||
static std::string x_string_operand(const char *YYCURSOR) {
|
||||
char *iter = YYCURSOR;
|
||||
std::string rv;
|
||||
/*!re2c
|
||||
* { throw std::invalid_argument("bad operand"); }
|
||||
|
||||
['] [^']* ['] | ["] [^"]* ["] {
|
||||
rv = std::string(iter+1, YYCURSOR-1);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
*/
|
||||
exit:
|
||||
char c = *YYCURSOR;
|
||||
if (isspace(c) || c == 0) return rv;
|
||||
throw std::invalid_argument("bad operand");
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int ovr_operand(const char *YYCURSOR) {
|
||||
int rv = 0;
|
||||
|
||||
/*!re2c
|
||||
* { throw std::invalid_argument("bad operand"); }
|
||||
[;*] | eof {
|
||||
return 1;
|
||||
}
|
||||
'ALL' {
|
||||
rv = -1;
|
||||
}
|
||||
'OFF' {
|
||||
rv = 0;
|
||||
}
|
||||
*/
|
||||
|
||||
char c = *YYCURSOR;
|
||||
if (isspace(c) || c == 0) return rv;
|
||||
|
||||
throw std::invalid_argument("bad operand");
|
||||
}
|
||||
|
||||
static std::string label_operand(const char *YYCURSOR, bool required = true) {
|
||||
std::string rv;
|
||||
char *iter = YYCURSOR;
|
||||
/*!re2c
|
||||
* { throw std::invalid_argument("bad operand"); }
|
||||
[;*] | eof {
|
||||
if (!required) return rv;
|
||||
throw std::invalid_argument("missing operand");
|
||||
}
|
||||
ident {
|
||||
rv = std::string(iter, YYCURSOR);
|
||||
goto exit;
|
||||
}
|
||||
*/
|
||||
|
||||
char c = *YYCURSOR;
|
||||
if (isspace(c) || c == 0) return rv;
|
||||
|
||||
throw std::invalid_argument("bad operand");
|
||||
}
|
||||
|
||||
|
||||
static std::string path_operand(const char *YYCURSOR, bool required = true) {
|
||||
std::string rv;
|
||||
char *iter = YYCURSOR;
|
||||
/*!re2c
|
||||
* { throw std::invalid_argument("bad operand"); }
|
||||
[;*] | eof {
|
||||
if (!required) return rv;
|
||||
throw std::invalid_argument("missing operand");
|
||||
}
|
||||
// don't allow leading quotes, eof, or comment chars
|
||||
[^;*\x00'"][^ \t]* {
|
||||
rv = std::string(iter, YYCURSOR);
|
||||
goto exit;
|
||||
}
|
||||
['] [^']* ['] | ["] [^"]* ["] {
|
||||
rv = std::string(iter+1, YYCURSOR-1);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
char c = *YYCURSOR;
|
||||
if (isspace(c) || c == 0) return rv;
|
||||
|
||||
throw std::invalid_argument("bad operand");
|
||||
}
|
||||
|
||||
|
||||
static void no_operand(const char *YYCURSOR) {
|
||||
/*!re2c
|
||||
* { throw std::invalid_argument("bad operand"); }
|
||||
[;*] | eof { return }
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
static std::string string_operand(const char *YYCURSOR, bool required = true) {
|
||||
|
||||
std::string rv;
|
||||
char *iter = YYCURSOR;
|
||||
/*!re2c
|
||||
* { throw std::invalid_argument("bad operand"); }
|
||||
[;*] | eof {
|
||||
if (!required) return rv;
|
||||
throw std::invalid_argument("missing operand");
|
||||
}
|
||||
['] [^']* ['] | ["] [^"]* ["] {
|
||||
rv = std::string(iter+1, YYCURSOR-1);
|
||||
goto exit;
|
||||
}
|
||||
*/
|
||||
|
||||
char c = *YYCURSOR;
|
||||
if (isspace(c) || c == 0) return rv;
|
||||
throw std::invalid_argument("bad operand");
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void parse_line(const char *YYCURSOR) {
|
||||
|
||||
unsigned cmd = 0;
|
||||
std::string label;
|
||||
|
||||
const char *iter = YYCURSOR;
|
||||
/*!re2c
|
||||
|
||||
* { throw std::invalid_argument("bad label") }
|
||||
[;*] | eof {
|
||||
return;
|
||||
}
|
||||
ws { goto opcode }
|
||||
ident / (ws|eof) {
|
||||
label(iter, YYCURSOR);
|
||||
goto opcode;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
|
||||
opcode:
|
||||
|
||||
|
||||
while (isspace(*YYCURSOR)) ++YYCURSOR;
|
||||
iter = YYCURSOR;
|
||||
|
||||
/*!re2c
|
||||
|
||||
* { throw std::invalid_argument("bad opcode"); }
|
||||
[;*]|eof { return 0; }
|
||||
|
||||
'=' / (ws|eof) { cmd = CMD_EQ; goto operand; }
|
||||
|
||||
[A-Za-z]+ / (ws|eof) {
|
||||
size_t = l YYCURSOR - iter;
|
||||
if (l > 3) l = 3;
|
||||
std::string s(iter, iter + l);
|
||||
for (char &c in s): c = std::toupper(c);
|
||||
auto iter = commands.find(s);
|
||||
if (!iter == commands.end()) {
|
||||
throw std::invalid_argument("bad opcode");
|
||||
}
|
||||
cmd = *iter;
|
||||
goto operand;
|
||||
}
|
||||
*/
|
||||
|
||||
operand:
|
||||
|
||||
while (isspace(*YYCURSOR)) ++YYCURSOR;
|
||||
iter = YYCURSOR;
|
||||
|
||||
std::string str_operand;
|
||||
long int_operand;
|
||||
|
||||
switch(cmd) {
|
||||
case CMD_LNK:
|
||||
case CMD_PUT:
|
||||
case CMD_ASM:
|
||||
case CMD_SAV:
|
||||
case CMD_LIB:
|
||||
case CMD_IF:
|
||||
case CMD_PFX:
|
||||
case CMD_IMP:
|
||||
case CMD_RES:
|
||||
case CMD_FIL:
|
||||
str_operand = path_operand(YYCURSOR);
|
||||
break;
|
||||
case CMD_ORG:
|
||||
case CMD_ADR:
|
||||
case CMD_DS:
|
||||
case CMD_KND:
|
||||
case CMD_VER:
|
||||
case CMD_ALI:
|
||||
case CMD_LKV:
|
||||
case CMD_DO:
|
||||
case CMD_EQU:
|
||||
case CMD_EQ:
|
||||
case CMD_GEQ:
|
||||
int_operand = number_operand(YYCURSOR);
|
||||
break;
|
||||
case CMD_TYP:
|
||||
int_operand = type_operand(YYCURSOR);
|
||||
break;
|
||||
case CMD_OVR:
|
||||
int_operand = ovr_operand(YYCURSOR);
|
||||
break;
|
||||
case CMD_POS:
|
||||
case CMD_LEN:
|
||||
str_operand = label_operand(YYCURSOR, false);
|
||||
break;
|
||||
case CMD_KBD:
|
||||
str_operand = string_operand(YYCURSOR, false);
|
||||
break;
|
||||
|
||||
case CMD_CMD:
|
||||
str_operand = string(YYCURSOR);
|
||||
break;
|
||||
|
||||
default:
|
||||
no_operand(YYCURSOR);
|
||||
break;
|
||||
}
|
||||
|
||||
switch(cmd) {
|
||||
|
||||
case CMD_NONE:
|
||||
case CMD_NOL: /* asm: default list off */
|
||||
case CMD_PUT: /* check if source file is outdated */
|
||||
case CMD_OVR: /* override outdated check and force assembly */
|
||||
case CMD_FAS: /* fast linker. only one SAV allowed */
|
||||
/* nop */
|
||||
break;
|
||||
|
||||
case CMD_LNK:
|
||||
/* link file ... */
|
||||
break;
|
||||
case CMD_ORG:
|
||||
/* set the link origin. also used as aux type */
|
||||
break;
|
||||
case CMD_ADR:
|
||||
/* set the file aux type */
|
||||
break;
|
||||
|
||||
case CMD_SAV:
|
||||
/* save linked file. for xl linker, specifies segment name */
|
||||
break;
|
||||
|
||||
case CMD_TYP:
|
||||
/* set the file type */
|
||||
break;
|
||||
|
||||
case CMD_EXT:
|
||||
/* print addresses of all resolved externals (not just errors)
|
||||
disabled after each SAV
|
||||
*/
|
||||
break;
|
||||
case CMD_ENT:
|
||||
/* print the entry list */
|
||||
/* flag symbol w ? if unused */
|
||||
break;
|
||||
case CMD_DAT:
|
||||
/* print the current date and time */
|
||||
break;
|
||||
|
||||
case CMD_END:
|
||||
/* end of command file (optional) */
|
||||
break;
|
||||
|
||||
case CMD_LIB:
|
||||
/* search directory for unresolved symbols */
|
||||
break;
|
||||
|
||||
case CMD_LKV:
|
||||
/* specify linker version */
|
||||
/* 0 = binary, 1 = Linker.GS, 2 = Linker.XL, 3 = convert to OMF object file */
|
||||
switch (int_operand) {
|
||||
case 0: throw std::runtime_error("binary linker not supported");
|
||||
case 3: throw std::runtime_error("object file linker not supported");
|
||||
case 1:
|
||||
case 2:
|
||||
/* default file type = S16 */
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("bad linker version");
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD_VER:
|
||||
/*specify OMF version. 1 or 2 */
|
||||
break;
|
||||
|
||||
case CMD_KND:
|
||||
/* set the OMF kind flag */
|
||||
/* 8-bit for v 1, 16-bit for v2 */
|
||||
break;
|
||||
|
||||
case CMD_ALI:
|
||||
/* OMF align field. default = 0 */
|
||||
break;
|
||||
|
||||
case CMD_DS:
|
||||
/* OMF RESSPC field */
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case CMD_ASM:
|
||||
default:
|
||||
throw std::runtime_error("opcode not supported");
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
int process_link_file(const std::string &path) {
|
||||
|
||||
FILE *fp;
|
||||
fp = fopen(path, "r");
|
||||
if (!fp) {
|
||||
warn("Unable to open %s", path.c_str());
|
||||
return -1;
|
||||
}
|
||||
|
||||
int no = 1;
|
||||
int errors = 0;
|
||||
const char *line = NULL;
|
||||
size_t cap = 0;
|
||||
for(;; ++no) {
|
||||
|
||||
ssize_t len = getline(&line, &cap, fp);
|
||||
if (len == 0) break;
|
||||
if (len < 0) {
|
||||
warn("read error");
|
||||
++errors;
|
||||
break;
|
||||
}
|
||||
/* strip trailing ws */
|
||||
while (len && isspace(line[len-1])) --len;
|
||||
line[len] = 0;
|
||||
if (len == 0) continue;
|
||||
|
||||
try {
|
||||
parse_line(line);
|
||||
} catch (std::exception &ex) {
|
||||
fprintf(stderr, "%s in line: %d\n", ex.what(), no);
|
||||
fprintf(stderr, "%s\n", line);
|
||||
if (++errors >= 10) {
|
||||
fputs("Too many errors, aborting\n", stderr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
free(line);
|
||||
return errors ? -1 : 0;
|
||||
}
|
95
unique_resource.h
Normal file
95
unique_resource.h
Normal file
|
@ -0,0 +1,95 @@
|
|||
#ifndef __unique_resource_h__
|
||||
#define __unique_resource_h__
|
||||
|
||||
#include <utility>
|
||||
|
||||
template <class T, class D>
|
||||
class unique_resource {
|
||||
public:
|
||||
typedef T element_type;
|
||||
typedef D deleter_type;
|
||||
|
||||
unique_resource() = default;
|
||||
unique_resource(const unique_resource &) = delete;
|
||||
unique_resource(unique_resource &&rhs) {
|
||||
swap(rhs);
|
||||
}
|
||||
|
||||
unique_resource(T t, D d): _pair(t,d), _active(true)
|
||||
{}
|
||||
|
||||
~unique_resource() {
|
||||
reset();
|
||||
}
|
||||
|
||||
unique_resource &operator=(const unique_resource &) = delete;
|
||||
unique_resource &operator=(unique_resource &&rhs) {
|
||||
if (this != std::addressof(rhs)) {
|
||||
reset();
|
||||
swap(rhs);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void swap(unique_resource & rhs) {
|
||||
if (this != std::addressof(rhs)) {
|
||||
std::swap(_active, rhs._active);
|
||||
std::swap(_pair, rhs._pair);
|
||||
}
|
||||
}
|
||||
|
||||
void reset(T t) {
|
||||
reset();
|
||||
_active = true;
|
||||
_pair.first = t;
|
||||
}
|
||||
|
||||
void reset(T t, D d) {
|
||||
reset();
|
||||
_active = true;
|
||||
_pair = std::make_pair(t, d);
|
||||
}
|
||||
|
||||
void reset() {
|
||||
if (_active) {
|
||||
(*_pair.second)(_pair.first);
|
||||
_active = false;
|
||||
}
|
||||
}
|
||||
|
||||
T release() {
|
||||
_active = false;
|
||||
return _pair.first;;
|
||||
}
|
||||
|
||||
T get() {
|
||||
return _pair.first;
|
||||
}
|
||||
|
||||
operator bool() const {
|
||||
return _active;
|
||||
}
|
||||
|
||||
D& get_deleter() {
|
||||
return _pair.second;
|
||||
}
|
||||
|
||||
const D& get_deleter() const {
|
||||
return _pair.second;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
std::pair<T, D> _pair;
|
||||
bool _active = false;
|
||||
};
|
||||
|
||||
#define MAKE_UNIQUE_RESOURCE(T, D) \
|
||||
unique_resource<decltype(T), decltype(D) *>(T, D)
|
||||
|
||||
template<class T, class D>
|
||||
unique_resource<T, D> make_unique_resource(T t, D d) {
|
||||
return unique_resource<T, D>(t, d);
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user