OpenCores
URL https://opencores.org/ocsvn/lxp32/lxp32/trunk

Subversion Repositories lxp32

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /lxp32/trunk/tools/src/lxp32asm
    from Rev 2 to Rev 6
    Reverse comparison

Rev 2 → Rev 6

/assembler.cpp
30,6 → 30,7
_state=Initial;
_currentFileName=filename;
processFileRecursive(filename);
 
// Examine symbol table
for(auto const &sym: _obj.symbols()) {
if(sym.second.type==LinkableObject::Unknown&&!sym.second.refs.empty()) {
40,6 → 41,8
throw std::runtime_error(msg.str());
}
}
for(auto const &sym: _exportedSymbols) _obj.exportSymbol(sym);
}
 
void Assembler::processFileRecursive(const std::string &filename) {
63,16 → 66,14
_line++;
}
if(_state!=Initial) throw std::runtime_error("Unexpected end of file");
_line=savedLine;
_state=savedState;
_currentFileName=savedFileName;
for(auto const &label: _currentLabels) {
_obj.addLocalSymbol(label,
static_cast<LinkableObject::Word>(_obj.codeSize()));
}
_currentLabels.clear();
if(!_currentLabels.empty())
throw std::runtime_error("Symbol definition must be followed by an instruction or data definition statement");
}
 
void Assembler::addIncludeSearchDir(const std::string &dir) {
127,7 → 128,7
else throw std::runtime_error(std::string("Unexpected character: \"")+ch+"\"");
break;
case Word:
if(std::isalnum(ch)||ch=='_'||ch=='@') word+=ch;
if(std::isalnum(ch)||ch=='_'||ch=='@'||ch=='+'||ch=='-') word+=ch;
else {
i--;
_state=Initial;
206,7 → 207,12
// Perform macro substitution
for(auto &token: list) {
auto it=_macros.find(token);
if(it==_macros.end()) newlist.push_back(std::move(token));
// Note: we don't expand a macro identifier in the #define statement
// since that would lead to counter-intuitive results
if(it==_macros.end()||
(newlist.size()==1&&newlist[0]=="#define")||
(newlist.size()==3&&newlist[1]==":"&&newlist[2]=="#define"))
newlist.push_back(std::move(token));
else for(auto const &replace: it->second) newlist.push_back(replace);
}
list=std::move(newlist);
233,7 → 239,7
else rva=elaborateInstruction(list);
for(auto const &label: _currentLabels) {
_obj.addLocalSymbol(label,rva);
_obj.addSymbol(label,rva);
}
_currentLabels.clear();
}
243,15 → 249,24
assert(!list.empty());
if(list[0]=="#define") {
if(list.size()<3) throw std::runtime_error("Wrong number of tokens in the directive");
if(!validateIdentifier(list[1])) throw std::runtime_error("Ill-formed identifier: \""+list[1]+"\"");
if(list.size()<3)
throw std::runtime_error("Wrong number of tokens in the directive");
if(_macros.find(list[1])!=_macros.end())
throw std::runtime_error("Macro \""+list[1]+"\" has been already defined");
if(!validateIdentifier(list[1]))
throw std::runtime_error("Ill-formed identifier: \""+list[1]+"\"");
_macros.emplace(list[1],TokenList(list.begin()+2,list.end()));
}
else if(list[0]=="#extern") {
else if(list[0]=="#export") {
if(list.size()!=2) std::runtime_error("Wrong number of tokens in the directive");
if(!validateIdentifier(list[1])) throw std::runtime_error("Ill-formed identifier: \""+list[1]+"\"");
_obj.addExternalSymbol(list[1]);
_exportedSymbols.push_back(list[1]);
}
else if(list[0]=="#import") {
if(list.size()!=2) std::runtime_error("Wrong number of tokens in the directive");
if(!validateIdentifier(list[1])) throw std::runtime_error("Ill-formed identifier: \""+list[1]+"\"");
_obj.addImportedSymbol(list[1]);
}
else if(list[0]=="#include") {
if(list.size()!=2) std::runtime_error("Wrong number of tokens in the directive");
auto filename=Utils::dequoteString(list[1]);
285,6 → 300,8
if(list.size()>2) throw std::runtime_error("Unexpected token: \""+list[2]+"\"");
std::size_t align=4;
if(list.size()>1) align=static_cast<std::size_t>(numericLiteral(list[1]));
if(!Utils::isPowerOf2(align)) throw std::runtime_error("Alignment must be a power of 2");
if(align<4) throw std::runtime_error("Alignment must be at least 4");
rva=_obj.addPadding(align);
}
else if(list[0]==".reserve") {
351,6 → 368,7
else if(list[0]=="jmp") encodeJmp(list);
else if(list[0]=="iret") encodeIret(list);
else if(list[0]=="lc") encodeLc(list);
else if(list[0]=="lcs") encodeLcs(list);
else if(list[0]=="lsb") encodeLsb(list);
else if(list[0]=="lub") encodeLub(list);
else if(list[0]=="lw") encodeLw(list);
358,6 → 376,7
else if(list[0]=="modu") encodeModu(list);
else if(list[0]=="mov") encodeMov(list);
else if(list[0]=="mul") encodeMul(list);
else if(list[0]=="neg") encodeNeg(list);
else if(list[0]=="nop") encodeNop(list);
else if(list[0]=="not") encodeNot(list);
else if(list[0]=="or") encodeOr(list);
456,7 → 475,7
arglist.push_back(std::move(a));
}
else if(list[i].size()==3&&list[i].substr(0,2)=="iv"&&
std::isdigit(list[i][2])) // interrupt vector
list[i][2]>='0'&&list[i][2]<='7') // interrupt vector
{
a.type=Operand::Register;
a.reg=240+(list[i][2]-'0');
598,11 → 617,6
void Assembler::encodeDivs(const TokenList &list) {
auto args=getOperands(list);
if(args.size()!=3) throw std::runtime_error("divs instruction requires 3 operands");
if(args[2].type==Operand::NumericLiteral&&args[2].i==0) {
std::cerr<<currentFileName()<<":"<<line()<<": ";
std::cerr<<"Warning: Division by zero"<<std::endl;
}
LinkableObject::Word w=0x54000000;
encodeDstOperand(w,args[0]);
encodeRd1Operand(w,args[1]);
613,11 → 627,6
void Assembler::encodeDivu(const TokenList &list) {
auto args=getOperands(list);
if(args.size()!=3) throw std::runtime_error("divu instruction requires 3 operands");
if(args[2].type==Operand::NumericLiteral&&args[2].i==0) {
std::cerr<<currentFileName()<<":"<<line()<<": ";
std::cerr<<"Warning: Division by zero"<<std::endl;
}
LinkableObject::Word w=0x50000000;
encodeDstOperand(w,args[0]);
encodeRd1Operand(w,args[1]);
656,8 → 665,13
_obj.addWord(w);
if(args[1].type==Operand::Identifier) {
auto symRva=_obj.addWord(static_cast<LinkableObject::Word>(args[1].i));
_obj.addReference(args[1].str,currentFileName(),line(),symRva);
LinkableObject::Reference ref;
ref.source=currentFileName();
ref.line=line();
ref.rva=_obj.addWord(0);
ref.offset=args[1].i;
ref.type=LinkableObject::Regular;
_obj.addReference(args[1].str,ref);
}
else if(args[1].type==Operand::NumericLiteral) {
_obj.addWord(static_cast<LinkableObject::Word>(args[1].i));
665,6 → 679,33
else throw std::runtime_error("\""+args[1].str+"\": bad argument");
}
 
void Assembler::encodeLcs(const TokenList &list) {
auto args=getOperands(list);
if(args.size()!=2) throw std::runtime_error("lcs instruction requires 2 operands");
LinkableObject::Word w=0xA0000000;
encodeDstOperand(w,args[0]);
if(args[1].type==Operand::NumericLiteral) {
if((args[1].i<-1048576||args[1].i>1048575)&&(args[1].i<0xFFF00000||args[1].i>0xFFFFFFFF))
throw std::runtime_error("\""+args[1].str+"\": out of range");
auto c=static_cast<LinkableObject::Word>(args[1].i)&0x1FFFFF;
w|=(c&0xFFFF);
w|=((c<<8)&0x1F000000);
_obj.addWord(w);
}
else if(args[1].type==Operand::Identifier) {
LinkableObject::Reference ref;
ref.source=currentFileName();
ref.line=line();
ref.rva=_obj.addWord(w);
ref.offset=args[1].i;
ref.type=LinkableObject::Short;
_obj.addReference(args[1].str,ref);
}
else throw std::runtime_error("\""+args[1].str+"\": bad argument");
}
 
void Assembler::encodeLsb(const TokenList &list) {
auto args=getOperands(list);
if(args.size()!=2) throw std::runtime_error("lsb instruction requires 2 operands");
735,6 → 776,16
_obj.addWord(w);
}
 
void Assembler::encodeNeg(const TokenList &list) {
// Note: "neg" is not a real instruction, but an alias for "sub dst, 0, src"
auto args=getOperands(list);
if(args.size()!=2) throw std::runtime_error("neg instruction requires 2 operands");
LinkableObject::Word w=0x44000000;
encodeDstOperand(w,args[0]);
encodeRd2Operand(w,args[1]);
_obj.addWord(w);
}
 
void Assembler::encodeNop(const TokenList &list) {
auto args=getOperands(list);
if(!args.empty()) throw std::runtime_error("nop instruction doesn't take operands");
/assembler.h
41,6 → 41,7
std::vector<std::string> _currentLabels;
std::string _currentFileName;
std::vector<std::string> _includeSearchDirs;
std::vector<std::string> _exportedSymbols;
public:
void processFile(const std::string &filename);
80,6 → 81,7
void encodeJmp(const TokenList &list);
void encodeIret(const TokenList &list);
void encodeLc(const TokenList &list);
void encodeLcs(const TokenList &list);
void encodeLsb(const TokenList &list);
void encodeLub(const TokenList &list);
void encodeLw(const TokenList &list);
87,6 → 89,7
void encodeModu(const TokenList &list);
void encodeMov(const TokenList &list);
void encodeMul(const TokenList &list);
void encodeNeg(const TokenList &list);
void encodeNop(const TokenList &list);
void encodeNot(const TokenList &list);
void encodeOr(const TokenList &list);
/linkableobject.cpp
96,7 → 96,7
_code[rva++]=static_cast<Byte>(value>>24);
}
 
void LinkableObject::addLocalSymbol(const std::string &name,Word rva) {
void LinkableObject::addSymbol(const std::string &name,Word rva) {
auto &data=symbol(name);
if(data.type!=Unknown) throw std::runtime_error("Symbol \""+name+"\" is already defined");
data.type=Local;
103,15 → 103,23
data.rva=rva;
}
 
void LinkableObject::addExternalSymbol(const std::string &name) {
void LinkableObject::addImportedSymbol(const std::string &name) {
auto &data=symbol(name);
if(data.type!=Unknown) throw std::runtime_error("Symbol \""+name+"\" is already defined");
data.type=External;
data.type=Imported;
}
 
void LinkableObject::addReference(const std::string &symbolName,const std::string &source,int line,Word rva) {
void LinkableObject::exportSymbol(const std::string &name) {
auto it=_symbols.find(name);
if(it==_symbols.end()||it->second.type==Unknown) throw std::runtime_error("Undefined symbol \""+name+"\"");
if(it->second.type==Imported) throw std::runtime_error("Symbol \""+name+"\" can't be both imported and exported at the same time");
if(it->second.type==Exported) throw std::runtime_error("Symbol \""+name+"\" has been already exported");
it->second.type=Exported;
}
 
void LinkableObject::addReference(const std::string &symbolName,const Reference &ref) {
auto &data=symbol(symbolName);
data.refs.push_back({source,line,rva});
data.refs.push_back(ref);
}
 
LinkableObject::SymbolData &LinkableObject::symbol(const std::string &name) {
120,7 → 128,7
 
const LinkableObject::SymbolData &LinkableObject::symbol(const std::string &name) const {
auto const it=_symbols.find(name);
if(it==_symbols.end()) throw std::runtime_error("Undefined symbol");
if(it==_symbols.end()) throw std::runtime_error("Undefined symbol \""+name+"\"");
return it->second;
}
 
151,10 → 159,18
out<<std::endl;
out<<"Start Symbol"<<std::endl;
out<<"\tName "<<Utils::urlEncode(sym.first)<<std::endl;
if(sym.second.type==Local) out<<"\tRVA 0x"<<Utils::hex(sym.second.rva)<<std::endl;
else out<<"\tExternal"<<std::endl;
if(sym.second.type==Local) out<<"\tType Local"<<std::endl;
else if(sym.second.type==Exported) out<<"\tType Exported"<<std::endl;
else out<<"\tType Imported"<<std::endl;
if(sym.second.type!=Imported) out<<"\tRVA 0x"<<Utils::hex(sym.second.rva)<<std::endl;
for(auto const &ref: sym.second.refs) {
out<<"\tRef "<<Utils::urlEncode(ref.source)<<" "<<ref.line<<" 0x"<<Utils::hex(ref.rva)<<std::endl;
out<<"\tRef ";
out<<Utils::urlEncode(ref.source)<<" ";
out<<ref.line<<" ";
out<<"0x"<<Utils::hex(ref.rva)<<" ";
out<<ref.offset<<" ";
if(ref.type==Regular) out<<"Regular"<<std::endl;
else if(ref.type==Short) out<<"Short"<<std::endl;
}
out<<"End Symbol"<<std::endl;
}
231,10 → 247,15
if(tokens.size()<2) throw std::runtime_error("Unexpected end of line");
name=Utils::urlDecode(tokens[1]);
}
else if(tokens[0]=="External") data.type=External;
else if(tokens[0]=="Type") {
if(tokens.size()<2) throw std::runtime_error("Unexpected end of line");
if(tokens[1]=="Local") data.type=Local;
else if(tokens[1]=="Exported") data.type=Exported;
else if(tokens[1]=="Imported") data.type=Imported;
else throw std::runtime_error("Bad symbol type");
}
else if(tokens[0]=="RVA") {
if(tokens.size()<2) throw std::runtime_error("Unexpected end of line");
data.type=Local;
data.rva=std::strtoul(tokens[1].c_str(),NULL,0);
}
else if(tokens[0]=="Ref") {
243,6 → 264,10
ref.source=Utils::urlDecode(tokens[1]);
ref.line=std::strtoul(tokens[2].c_str(),NULL,0);
ref.rva=std::strtoul(tokens[3].c_str(),NULL,0);
ref.offset=std::strtoll(tokens[4].c_str(),NULL,0);
if(tokens[5]=="Regular") ref.type=Regular;
else if(tokens[5]=="Short") ref.type=Short;
else throw std::runtime_error("Invalid reference type: \""+tokens[5]+"\"");
data.refs.push_back(std::move(ref));
}
}
/linkableobject.h
20,12 → 20,17
public:
typedef unsigned char Byte;
typedef std::uint32_t Word;
typedef std::int_least64_t Integer;
enum SymbolType {Unknown,Local,External};
enum SymbolType {Unknown,Local,Exported,Imported};
enum RefType {Regular,Short};
struct Reference {
std::string source;
int line;
Word rva;
Integer offset;
RefType type;
};
struct SymbolData {
SymbolType type=Unknown;
32,6 → 37,7
Word rva;
std::vector<Reference> refs;
};
typedef std::map<std::string,SymbolData> SymbolTable;
private:
61,9 → 67,10
Word getWord(Word rva) const;
void replaceWord(Word rva,Word value);
void addLocalSymbol(const std::string &name,Word rva);
void addExternalSymbol(const std::string &name);
void addReference(const std::string &symbolName,const std::string &source,int line,Word rva);
void addSymbol(const std::string &name,Word rva);
void addImportedSymbol(const std::string &name);
void exportSymbol(const std::string &name);
void addReference(const std::string &symbolName,const Reference &ref);
SymbolData &symbol(const std::string &name);
const SymbolData &symbol(const std::string &name) const;
/linker.cpp
9,6 → 9,7
#include "linker.h"
 
#include "linkableobject.h"
#include "utils.h"
 
#include <iostream>
#include <fstream>
16,6 → 17,7
#include <map>
#include <stdexcept>
#include <cassert>
#include <algorithm>
 
void Linker::addObject(LinkableObject &obj) {
_objects.push_back(&obj);
29,14 → 31,8
// Determine entry point
if(_objects.size()==1) _entryObject=_objects[0];
else {
auto const it=_globalSymbolTable.find("entry");
if(it==_globalSymbolTable.end())
throw std::runtime_error("Entry point not defined: cannot find \"entry\" symbol");
if(it->second.rva!=0)
throw std::runtime_error(it->second.obj->name()+": Entry point must refer to the start of the object");
_entryObject=it->second.obj;
}
else if(_entryObject==nullptr)
throw std::runtime_error("Entry point not defined: cannot find \"entry\" or \"Entry\" symbol");
// Assign virtual addresses
placeObjects();
46,6 → 42,7
// Write binary data
writeObjects(writer);
_bytesWritten=writer.size();
}
 
void Linker::setBase(LinkableObject::Word base) {
60,6 → 57,41
_imageSize=size;
}
 
void Linker::generateMap(std::ostream &s) {
// Calculate the maximum length of a symbol name
std::size_t len=0;
for(auto const &obj: _objects) {
for(auto const &sym: obj->symbols()) {
if(sym.second.type!=LinkableObject::Imported)
len=std::max(len,sym.first.size());
}
}
len=std::max(len+3,std::size_t(8)); // width of the first column
s<<"Image base address: "<<Utils::hex(_base)<<std::endl;
s<<"Object alignment: "<<_align<<std::endl;
s<<"Image size: "<<(_bytesWritten/4)<<" words"<<std::endl;
s<<"Number of objects: "<<_objects.size()<<std::endl;
s<<std::endl;
for(auto const &obj: _objects) {
s<<"Object \""<<obj->name()<<"\" at address "<<Utils::hex(obj->virtualAddress())<<std::endl;
s<<std::endl;
std::multimap<LinkableObject::Word,std::pair<std::string,LinkableObject::SymbolData> > sorted;
for(auto const &sym: obj->symbols()) sorted.emplace(sym.second.rva,sym);
for(auto const &sym: sorted) {
if(sym.second.second.type==LinkableObject::Imported) continue;
s<<sym.second.first;
s<<std::string(len-sym.second.first.size(),' ');
s<<Utils::hex(obj->virtualAddress()+sym.second.second.rva);
if(sym.second.second.type==LinkableObject::Local) s<<" Local";
else s<<" Exported";
s<<std::endl;
}
s<<std::endl;
}
}
 
/*
* Private members
*/
67,14 → 99,31
void Linker::buildSymbolTable() {
_globalSymbolTable.clear();
// Build a table of exported symbols from all modules
for(auto const &obj: _objects) {
auto const &table=obj->symbols();
for(auto const &item: table) {
if((item.first=="entry"||item.first=="Entry")&&item.second.type!=LinkableObject::Imported) {
if(_entryObject) {
std::ostringstream msg;
msg<<obj->name()<<": Duplicate definition of the entry symbol ";
msg<<"(previously defined in "<<_entryObject->name()<<")";
throw std::runtime_error(msg.str());
}
if(item.second.rva!=0) {
std::ostringstream msg;
msg<<obj->name()<<": ";
msg<<"Entry point must refer to the start of the object";
throw std::runtime_error(msg.str());
}
_entryObject=obj;
}
if(item.second.type==LinkableObject::Local) continue;
// Insert item to the global symbol table if it doesn't exist yet
auto it=_globalSymbolTable.emplace(item.first,GlobalSymbolData()).first;
 
// If the symbol is local, check that it has not been already defined in another object
if(item.second.type==LinkableObject::Local) {
// Check that the symbol has not been already defined in another object
if(item.second.type==LinkableObject::Exported) {
if(it->second.obj) {
std::ostringstream msg;
msg<<obj->name()<<": Duplicate definition of \""<<item.first;
84,12 → 133,28
it->second.obj=obj;
it->second.rva=item.second.rva;
}
 
// Merge reference tables
for(auto const &ref: item.second.refs) it->second.refs.emplace(obj,ref.rva);
if(!item.second.refs.empty()) it->second.refs.insert(obj);
}
}
// Check that local symbols don't shadow the public ones
for(auto const &obj: _objects) {
auto const &table=obj->symbols();
for(auto const &item: table) {
if(item.second.type!=LinkableObject::Local) continue;
auto it=_globalSymbolTable.find(item.first);
if(it==_globalSymbolTable.end()) continue;
if(!it->second.obj) continue;
if(item.first==it->first) {
std::ostringstream msg;
msg<<obj->name()<<": Local symbol \""<<item.first<<"\" shadows the public one ";
msg<<"(defined in "<<it->second.obj->name()<<")";
throw std::runtime_error(msg.str());
}
}
}
// Check that no undefined symbols remain
for(auto const &item: _globalSymbolTable) {
if(item.second.obj==nullptr&&!item.second.refs.empty()) {
96,7 → 161,7
std::ostringstream msg;
msg<<"Undefined symbol: \""<<item.first<<"\"";
auto const it=item.second.refs.begin();
msg<<" (referenced from "<<it->first->name()<<")";
msg<<" (referenced from "<<(*it)->name()<<")";
throw std::runtime_error(msg.str());
}
}
109,12 → 174,31
if(_objects.size()>1) {
for(auto it=_objects.begin();it!=_objects.end();++it) {
if(*it==_entryObject) {
std::swap(*it,_objects[0]);
_objects.erase(it);
break;
}
}
_objects.insert(_objects.begin(),_entryObject);
}
// Remove unreferenced objects
if(_objects.size()>1) {
std::set<const LinkableObject*> used;
markAsUsed(_objects[0],used);
for(auto it=_objects.begin();it!=_objects.end();) {
if(used.find(*it)==used.end()) {
std::cerr<<"Linker warning: skipping an unreferenced object \"";
std::cerr<<(*it)->name()<<"\""<<std::endl;
for(auto sym=_globalSymbolTable.begin();sym!=_globalSymbolTable.end();) {
if(sym->second.obj==*it) sym=_globalSymbolTable.erase(sym);
else ++sym;
}
it=_objects.erase(it);
}
else ++it;
}
}
// Set base addresses
for(auto it=_objects.begin();it!=_objects.end();++it) {
(*it)->setVirtualAddress(currentBase);
126,14 → 210,33
 
void Linker::relocateObject(LinkableObject *obj) {
for(auto const &sym: obj->symbols()) {
auto it=_globalSymbolTable.find(sym.first);
assert(it!=_globalSymbolTable.end());
if(it->second.refs.empty()) continue;
assert(it->second.obj);
auto addr=it->second.obj->virtualAddress()+it->second.rva;
LinkableObject::Word addr;
if(sym.second.refs.empty()) continue;
if(sym.second.type==LinkableObject::Local) addr=obj->virtualAddress()+sym.second.rva;
else {
auto it=_globalSymbolTable.find(sym.first);
assert(it!=_globalSymbolTable.end());
assert(it->second.obj);
addr=it->second.obj->virtualAddress()+it->second.rva;
}
for(auto const &ref: sym.second.refs) {
auto offset=obj->getWord(ref.rva);
obj->replaceWord(ref.rva,addr+offset);
if(ref.type==LinkableObject::Regular) obj->replaceWord(ref.rva,addr+ref.offset);
else {
auto target=static_cast<LinkableObject::Word>(addr+ref.offset);
if(target>0xFFFFF&&target<0xFFF00000) {
std::ostringstream msg;
msg<<"Address 0x"<<Utils::hex(target)<<" is out of the range for a short reference";
msg<<" (referenced from "<<ref.source<<":"<<ref.line<<")";
throw std::runtime_error(msg.str());
}
target&=0x1FFFFF;
auto w=obj->getWord(ref.rva);
w|=(target&0xFFFF);
w|=((target<<8)&0x1F000000);
obj->replaceWord(ref.rva,w);
}
}
}
}
157,3 → 260,13
else if(currentSize<_imageSize) writer.pad(_imageSize-currentSize);
}
}
 
void Linker::markAsUsed(const LinkableObject *obj,std::set<const LinkableObject*> &used) {
if(used.find(obj)!=used.end()) return; // already processed
used.insert(obj);
for(auto const &sym: _globalSymbolTable) {
for(auto const &ref: sym.second.refs) {
if(ref==obj) markAsUsed(sym.second.obj,used);
}
}
}
/linker.h
17,16 → 17,17
#include <map>
#include <vector>
#include <string>
#include <set>
 
class Linker {
struct GlobalSymbolData {
LinkableObject *obj=nullptr;
LinkableObject::Word rva=0;
std::multimap<const LinkableObject*,LinkableObject::Word> refs;
std::set<const LinkableObject*> refs;
};
std::vector<LinkableObject*> _objects;
LinkableObject *_entryObject;
LinkableObject *_entryObject=nullptr;
std::map<std::string,GlobalSymbolData> _globalSymbolTable;
// Various output options
33,6 → 34,7
LinkableObject::Word _base=0;
std::size_t _align=4;
std::size_t _imageSize=0;
std::size_t _bytesWritten=0;
public:
void addObject(LinkableObject &obj);
void link(OutputWriter &writer);
39,11 → 41,13
void setBase(LinkableObject::Word base);
void setAlignment(std::size_t align);
void setImageSize(std::size_t size);
void generateMap(std::ostream &s);
private:
void buildSymbolTable();
void placeObjects();
void relocateObject(LinkableObject *obj);
void writeObjects(OutputWriter &writer);
void markAsUsed(const LinkableObject *obj,std::set<const LinkableObject*> &used);
};
 
#endif
/main.cpp
8,6 → 8,7
 
#include "assembler.h"
#include "linker.h"
#include "utils.h"
 
#include <iostream>
#include <fstream>
25,6 → 26,7
bool compileOnly=false;
std::string outputFileName;
std::string mapFileName;
std::vector<std::string> includeSearchDirs;
LinkableObject::Word base=0;
std::size_t align=4;
38,7 → 40,7
os<<" "<<program<<" [ option(s) | input file(s) ]"<<std::endl<<std::endl;
os<<"Options:"<<std::endl;
os<<" -a <align> Section alignment (default: 4)"<<std::endl;
os<<" -a <align> Object alignment (default: 4)"<<std::endl;
os<<" -b <addr> Base address (default: 0)"<<std::endl;
os<<" -c Compile only (don't link)"<<std::endl;
os<<" -f <fmt> Output file format (see below)"<<std::endl;
45,12 → 47,14
os<<" -h, --help Display a short help message"<<std::endl;
os<<" -i <dir> Add directory to the list of directories used to search"<<std::endl;
os<<" for included files (multiple directories can be specified)"<<std::endl;
os<<" -m <file> Generate map file"<<std::endl;
os<<" -o <file> Output file name"<<std::endl;
os<<" -s <size> Output image size"<<std::endl;
os<<" -- Do not interpret subsequent arguments as options"<<std::endl;
os<<std::endl;
os<<"Section alignment and image size must be multiples of 4."<<std::endl;
os<<"Base address must be a multiple of section alignment."<<std::endl;
os<<"Object alignment must be a power of two and can't be less than 4."<<std::endl;
os<<"Base address must be a multiple of object alignment."<<std::endl;
os<<"Image size must be a multiple of 4."<<std::endl;
os<<std::endl;
os<<"Output file formats:"<<std::endl;
67,6 → 71,8
std::ifstream in(filename,std::ios_base::in);
if(!in) return false;
if(in.tellg()==static_cast<std::ifstream::pos_type>(-1))
return false; // the stream is not seekable
std::vector<char> buf(idSize);
in.read(buf.data(),idSize);
84,7 → 90,7
bool noMoreOptions=false;
std::cout<<"LXP32 Platform Assembler and Linker"<<std::endl;
std::cout<<"Copyright (c) 2016 by Alex I. Kuznetsov"<<std::endl;
std::cout<<"Copyright (c) 2016-2019 by Alex I. Kuznetsov"<<std::endl;
if(argc<=1) {
displayUsage(std::cout,argv[0]);
101,11 → 107,12
}
try {
options.align=std::stoul(argv[i],nullptr,0);
if(options.align%4!=0||options.align==0) throw std::exception();
if(!Utils::isPowerOf2(options.align)) throw std::exception();
if(options.align<4) throw std::exception();
alignmentSpecified=true;
}
catch(std::exception &) {
throw std::runtime_error("Invalid section alignment");
throw std::runtime_error("Invalid object alignment");
}
}
else if(!strcmp(argv[i],"-b")) {
115,7 → 122,6
}
try {
options.base=std::stoul(argv[i],nullptr,0);
//if(options.base%4!=0) throw std::exception();
baseSpecified=true;
}
catch(std::exception &) {
148,6 → 154,13
}
options.includeSearchDirs.push_back(argv[i]);
}
else if(!strcmp(argv[i],"-m")) {
if(++i==argc) {
displayUsage(std::cerr,argv[0]);
return EXIT_FAILURE;
}
options.mapFileName=argv[i];
}
else if(!strcmp(argv[i],"-o")) {
if(++i==argc) {
displayUsage(std::cerr,argv[0]);
172,11 → 185,11
}
if(options.base%options.align!=0)
throw std::runtime_error("Base address must be a multiple of section alignment");
throw std::runtime_error("Base address must be a multiple of object alignment");
if(options.compileOnly) {
if(alignmentSpecified)
std::cerr<<"Warning: Section alignment is ignored in compile-only mode"<<std::endl;
std::cerr<<"Warning: Object alignment is ignored in compile-only mode"<<std::endl;
if(baseSpecified)
std::cerr<<"Warning: Base address is ignored in compile-only mode"<<std::endl;
if(formatSpecified)
183,6 → 196,8
std::cerr<<"Warning: Output format is ignored in compile-only mode"<<std::endl;
if(options.imageSize>0)
std::cerr<<"Warning: Image size is ignored in compile-only mode"<<std::endl;
if(!options.mapFileName.empty())
std::cerr<<"Warning: Map file is not generated in compile-only mode"<<std::endl;
}
if(inputFiles.empty())
278,6 → 293,14
std::cerr<<"Linker error: "<<ex.what()<<std::endl;
return EXIT_FAILURE;
}
std::cout<<writer->size()/4<<" words written"<<std::endl;
if(!options.mapFileName.empty()) {
std::ofstream out(options.mapFileName);
if(!out) throw std::runtime_error("Cannot open file \""+options.mapFileName+"\" for writing");
linker.generateMap(out);
}
}
catch(std::exception &ex) {
std::cerr<<"Error: "<<ex.what()<<std::endl;
/outputwriter.cpp
22,6 → 22,11
* OutputWriter members
*/
 
void OutputWriter::write(const char *data,std::size_t n) {
writeData(data,n);
_size+=n;
}
 
void OutputWriter::pad(std::size_t size) {
static char zeros[256]; // static objects are zero-initialized
while(size>0) {
31,6 → 36,10
}
}
 
std::size_t OutputWriter::size() const {
return _size;
}
 
/*
* BinaryOutputWriter members
*/
42,7 → 51,7
if(!_os) throw std::runtime_error("Cannot open \""+filename+"\" for writing");
}
 
void BinaryOutputWriter::write(const char *data,std::size_t n) {
void BinaryOutputWriter::writeData(const char *data,std::size_t n) {
_os.write(data,n);
}
 
70,7 → 79,7
}
}
 
void TextOutputWriter::write(const char *data,std::size_t n) {
void TextOutputWriter::writeData(const char *data,std::size_t n) {
while(n>0) {
assert(_buf.size()<4);
auto count=std::min(4-_buf.size(),n);
/outputwriter.h
19,11 → 19,15
*/
 
class OutputWriter {
std::size_t _size=0;
public:
virtual ~OutputWriter() {}
virtual void write(const char *data,std::size_t n)=0;
virtual void write(const char *data,std::size_t n);
virtual void abort() {}
void pad(std::size_t size);
std::size_t size() const;
protected:
virtual void writeData(const char *data,std::size_t n)=0;
};
 
/*
35,8 → 39,9
std::ofstream _os;
public:
BinaryOutputWriter(const std::string &filename);
virtual void write(const char *data,std::size_t n) override;
virtual void abort() override;
protected:
virtual void writeData(const char *data,std::size_t n) override;
};
 
/*
54,8 → 59,9
public:
TextOutputWriter(const std::string &filename,Format f);
~TextOutputWriter();
virtual void write(const char *data,std::size_t n) override;
virtual void abort() override;
protected:
virtual void writeData(const char *data,std::size_t n) override;
};
 
#endif
/utils.h
52,6 → 52,11
bool ishexdigit(char ch);
bool isoctdigit(char ch);
template <typename T> bool isPowerOf2(const T &x) {
static_assert(std::is_integral<T>::value,"Argument must be of integral type");
return (x!=0)&&((x&(x-1))==0);
}
}
 
#endif

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.