568 lines · 16.6 KB · C++
RawDownload
#include <fstream>#include <iostream>#include <unordered_map>#include <unordered_set>#include <set>#include <string>#include "BinaryIO.h"#include <stdint.h>#include <vector>#include <assert.h>#include <ctype.h>#include <sstream>#include <memory> using std::string;using std::vector;using std::unordered_map;using std::unordered_set; bool verbose = false;bool shouldSortModules = true;bool addMacsbugNames = true;bool functionSections = true;bool dataSections = true;bool dataInText = false; using stringid = int;unordered_map<stringid,stringid>    sectionMap;unordered_map<stringid,string>    stringDictionary;unordered_set<stringid> localLabels; enum RecordType {    kPad = 0,    kFirst = 1,    kLast = 2,    kComment = 3,    kDictionary = 4,    kModule = 5,    kEntryPoint = 6,    kSize = 7,    kContent = 8,    kReference = 9,    kComputedRef = 10,    kFilename = 11}; enum ModuleFlags {    kData = 0x01,   // default code    kExtern = 0x08  // default local}; enum ReferenceFlags {    // flags field of kReference    k16BitPatch = 0x10,    // default 32Bit    kFromData = 0x01,    // default fromCode    kA5Relative = 0x80,    // default absolute     kUnknownReferenceFlags = 0x6E    // rather a lot, isn't it?        // The following flags are known to exist from DumpOBJ,        // but their value is unknown as I haven't actually seen them yet:        // k32BitOffsets (default k16BitOffsets)}; enum ComputedReferenceFlags {    kDifference = 0x80}; enum ContentFlags {    // kData = 0x01 // ?    kContentOffset = 0x08,    kContentRepeat = 0x10}; string encodeIdentifier(stringid id){    const string& s = stringDictionary[id];    std::ostringstream ss;     if(localLabels.find(id) != localLabels.end())        ss << "L" << id << ".";     if(s.empty() || isdigit(s[0]))        ss << "__z";     for(char c : s)    {        if(c == '_' || isalnum(c))            ss << c;        else        {            ss << "__z" << (int) c << "_";        }    }     return ss.str();} struct Reloc{    int size;    stringid name1 = -1;    stringid name2 = -1;     int write(std::ostream& out, uint8_t *p);}; int Reloc::write(std::ostream& out, uint8_t *p){    if(size == 2)    {        out << "\t.short ";        int val = (int)p[0] * 256 + p[1];         out << encodeIdentifier(name1);        if(name2 != -1)            out << " - " << encodeIdentifier(name2);        if(val > 0)            out << " + " << val;        else if(val < 0)            out << " - " << -val;        if(name2 == -1)            out << "-.";        out << std::endl;        return 2;    }    else if(size == 4)    {        out << "\t.long ";        int val = ((int)p[0] << 24) | ((int)p[1] << 16) | ((int)p[2] << 8) | p[3];         out << encodeIdentifier(name1);        if(name2 != -1)            out << " - " << encodeIdentifier(name2);        if(val > 0)            out << " + " << val;        else if(val < 0)            out << " - " << -val;        out << std::endl;        return 4;    }    else    {        assert(false);        return 1;    }} struct Module{    stringid name;    stringid segment;    bool isData;    vector<uint8_t> bytes;    unordered_map<uint32_t, vector<stringid>> labels;    unordered_map<uint32_t, Reloc> relocs;     std::vector<std::weak_ptr<Module>> nearrefs;     void write(std::ostream& out);}; void Module::write(std::ostream& out){        string encodedName = encodeIdentifier(sectionMap[name]);     if(isData && !dataInText)    {        if(dataSections)            out << "\t.section .data." << encodedName << ",\"aw\"\n";        else            out << "\t.data\n";        if(bytes.size() >= 2)            out << "\t.align 2,0\n";    }    else    {        if(functionSections)            out << "\t.section    .text." << encodedName << ",\"ax\",@progbits\n";        else            out << "\t.section    .text,\"ax\",@progbits\n";        out << "\t.align 2,0\n";    }     for(uint32_t offset = 0; offset < bytes.size();)    {        auto labelP = labels.find(offset);        if(labelP != labels.end())        {            for(stringid rawLabel : labelP->second)            {                string label = encodeIdentifier(rawLabel);                if(localLabels.find(rawLabel) == localLabels.end())                    out << "\t.globl " << label << "\n";                out << label << ":\n";            }        }         auto relocP = relocs.find(offset);        if(relocP != relocs.end())        {            offset += relocP->second.write(out, &bytes[offset]);        }        else        {            out << "\t.byte " << (int)bytes[offset] << "\n";            offset++;        }    }    if(addMacsbugNames && !isData)    {        if(functionSections)            out << "\t.section    .text." << encodedName << ".macsbug,\"ax\",@progbits\n";        if(encodedName.size() < 32)            out << "\t.byte " << (encodedName.size() | 0x80) << "\n";        else            out << "\t.byte 0x80\n"                << "\t.byte " << encodedName.size() << "\n";        out << "\t.ascii \"" << encodedName << "\"\n";        out << "\t.align 2,0\n\t.short 0\n";    }    out << "# ######\n\n";} void sortModules(std::vector<std::shared_ptr<Module>>& modules){    std::set<stringid> unemitted;    for(auto& m : modules)        unemitted.insert(m->name);        std::unordered_map<stringid, std::shared_ptr<Module>> nameMap;    for(auto& m : modules)        for(auto& l : m->labels)            for(auto& str : l.second)                nameMap[str] = m;            for(auto& m : modules)        for(auto& r : m->relocs)        {            if(r.second.size != 2)                continue;            if(r.second.name2 == -1)            {                if(auto p = nameMap.find(r.second.name1); p != nameMap.end())                {                    std::shared_ptr<Module> m1 = p->second;                    m1->nearrefs.push_back(m);                    m->nearrefs.push_back(m1);                }            }            else            {                auto p1 = nameMap.find(r.second.name1);                auto p2 = nameMap.find(r.second.name2);                 if(p1 != nameMap.end() && p2 != nameMap.end())                {                    std::shared_ptr<Module> m1 = p1->second;                    std::shared_ptr<Module> m2 = p2->second;                    m1->nearrefs.push_back(m2);                    m2->nearrefs.push_back(m1);                }            }        }         std::vector<std::shared_ptr<Module>> sorted;    sorted.reserve(modules.size());        auto p = sorted.begin();        while(!unemitted.empty())    {        while(p != sorted.end())        {            for(auto& m2weak : (*p)->nearrefs)            {                if(std::shared_ptr<Module> m2 = m2weak.lock())                {                    auto unemittedP = unemitted.find(m2->name);                    if(unemittedP != unemitted.end())                    {                        sorted.push_back(m2);                        unemitted.erase(unemittedP);                    }                }            }            ++p;        }        if(!unemitted.empty())        {            sorted.push_back(nameMap[*unemitted.begin()]);            unemitted.erase(unemitted.begin());        }    }        sorted.swap(modules);} int main(int argc, char* argv[]){    if(argc != 2)    {        std::cerr << "Usage: ConvertObj mpw.o > retro68.s\n";        return 1;    }    std::ifstream in(argv[1]);    if(!in)    {        std::cerr << "Could not read input file \"" << argv[1] << "\"\n";        std::cerr << "Usage: ConvertObj mpw.o > retro68.s\n";        return 1;    }        std::shared_ptr<Module> module;    std::vector<std::shared_ptr<Module>> modules;      {        int firstRecord = byte(in);        /*int flags =*/ byte(in);        int version = word(in);         if(firstRecord != kFirst)        {            std::cerr << "Not an MPW object file.\n";            return 1;        }         if(version > 3)        {            std::cerr << "Unknown/invalid MPW object file version "                << version << std::endl;            return 1;        }         if(verbose)        {            std::cerr << "First\n";            std::cerr << "Version: " << version << std::endl;        }    }     std::cout << "\t.text\n\t.align 2\n";     for(bool endOfObject = false; !endOfObject;) {        if(verbose)            std::cerr << std::hex << in.tellg() << ": ";        int recordType = byte(in);        if(!in)        {            std::cerr << "Unexpected End of File\n";            return 1;        }         if(verbose)            std::cerr << "Record: " << recordType << std::endl;          switch(recordType)        {            case kPad:                if(verbose)                    std::cerr << "Pad\n";                break;            case kComment:                {                    /*int flags =*/ byte(in);                    int size = word(in);                    size -= 4;                    if(verbose)                        std::cerr << "Comment: ";                    while(size-- > 0)                    {                        char c = byte(in);                        if(verbose)                            std::cerr << c;                    }                    if(verbose)                        std::cerr << std::endl;                }                break;            case kDictionary:                {                    /*int flags =*/ byte(in);                    if(verbose)                        std::cerr << "Dictionary\n";                    int sz = word(in);                    int stringId = word(in);                    int end = (int)(in.tellg()) - 6 + sz;                    while(in.tellg() < end)                    {                        int n = byte(in);                        string s;                        for(int i = 0; i < n; i++)                            s += (char) byte(in);                        if(verbose)                            std::cerr << s << std::endl;                        stringDictionary[stringId++] = s;                    }                }                break;            case kModule:                {                    int flags = byte(in);                    stringid name = word(in);                    sectionMap[name] = name;                    stringid segment = word(in);                                        if(verbose)                        std::cerr << "Module " << stringDictionary[name] << "(" << stringDictionary[segment] << "), flags = " << flags << "\n";                     if((flags & kExtern) == 0)                        localLabels.insert(name);                     module.reset(new Module());                    module->name = name;                    module->segment = segment;                    module->isData = (flags & kData) != 0;                    module->labels[0].push_back(name);                    modules.push_back(module);                }                break;            case kContent:                {                    int flags = byte(in);                    int sz = word(in) - 4;                    uint32_t offset = 0;                    if(flags & kContentOffset)                    {                         offset = longword(in);                        sz -= 4;                    }                    int repeat = 1;                    if(flags & kContentRepeat)                    {                        repeat = word(in);                        sz -= 2;                    }                       if(verbose)                        std::cerr << "Content (offset = " << offset << ", size = " << sz << ", repeat = " << repeat <<  ")\n";                     assert(module.get());                    if(module->bytes.size() < offset + sz * repeat)                        module->bytes.resize(offset + sz * repeat);                    in.read((char*) &module->bytes[offset], sz);                    while(--repeat > 0)                    {                        std::copy(module->bytes.begin() + offset, module->bytes.begin() + offset + sz,                                  module->bytes.begin() + offset + sz);                        offset += sz;                    }                }                break;            case kSize:                {                    /*int flags =*/ byte(in);                    long size = longword(in);                    if(verbose)                        std::cerr << "Size " << size << "\n";                    assert(module.get());                    module->bytes.resize(size);                }                break;            case kReference:                {                    int flags = byte(in);                    int sz = word(in);                    int end = (int)(in.tellg()) - 4 + sz;                    stringid name = word(in);                     if(verbose)                        std::cerr << "Reference to " << stringDictionary[name] << " at\n";                    Reloc reloc;                    reloc.name1 = name;                     if(flags & kUnknownReferenceFlags)                    {                        std::cerr << "Unknown relocation flags: 0x" << std::hex << flags << std::endl;                        std::cerr << "Cannot convert this file.\n";                        std::exit(1);                    }                    if(flags & kA5Relative)                    {                        std::cerr << "Unsupported relocation flags: 0x" << std::hex << flags << std::endl;                        std::cerr << "MPW .o files with near-model global variables or calls to imported functions will not work.\n";                        std::cerr << "Cannot convert this file.\n";                        std::exit(1);                    }                    flags &= ~kFromData;    // FIXME: sticking data bits in the text section, not nice, but might sometimes work                     reloc.size = (flags & k16BitPatch ? 2 : 4);                     assert(module);                     while(in.tellg() < end)                    {                        int offset = word(in);                        if(verbose)                            std::cerr << "  " << offset << std::endl;

Lines 1–500 of 568.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t