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

Subversion Repositories lxp32

[/] [lxp32/] [trunk/] [tools/] [src/] [lxp32asm/] [linker.cpp] - Blame information for rev 2

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 ring0_mipt
/*
2
 * Copyright (c) 2016 by Alex I. Kuznetsov.
3
 *
4
 * Part of the LXP32 CPU IP core.
5
 *
6
 * This module implements members of the Linker class.
7
 */
8
 
9
#include "linker.h"
10
 
11
#include "linkableobject.h"
12
 
13
#include <iostream>
14
#include <fstream>
15
#include <sstream>
16
#include <map>
17
#include <stdexcept>
18
#include <cassert>
19
 
20
void Linker::addObject(LinkableObject &obj) {
21
        _objects.push_back(&obj);
22
}
23
 
24
void Linker::link(OutputWriter &writer) {
25
        if(_objects.empty()) throw std::runtime_error("Object set is empty");
26
 
27
// Merge symbol tables
28
        buildSymbolTable();
29
 
30
// Determine entry point
31
        if(_objects.size()==1) _entryObject=_objects[0];
32
        else {
33
                auto const it=_globalSymbolTable.find("entry");
34
                if(it==_globalSymbolTable.end())
35
                        throw std::runtime_error("Entry point not defined: cannot find \"entry\" symbol");
36
                if(it->second.rva!=0)
37
                        throw std::runtime_error(it->second.obj->name()+": Entry point must refer to the start of the object");
38
                _entryObject=it->second.obj;
39
        }
40
 
41
// Assign virtual addresses
42
        placeObjects();
43
 
44
// Perform relocations
45
        for(auto &obj: _objects) relocateObject(obj);
46
 
47
// Write binary data
48
        writeObjects(writer);
49
}
50
 
51
void Linker::setBase(LinkableObject::Word base) {
52
        _base=base;
53
}
54
 
55
void Linker::setAlignment(std::size_t align) {
56
        _align=align;
57
}
58
 
59
void Linker::setImageSize(std::size_t size) {
60
        _imageSize=size;
61
}
62
 
63
/*
64
 * Private members
65
 */
66
 
67
void Linker::buildSymbolTable() {
68
        _globalSymbolTable.clear();
69
 
70
        for(auto const &obj: _objects) {
71
                auto const &table=obj->symbols();
72
                for(auto const &item: table) {
73
// Insert item to the global symbol table if it doesn't exist yet
74
                        auto it=_globalSymbolTable.emplace(item.first,GlobalSymbolData()).first;
75
 
76
// If the symbol is local, check that it has not been already defined in another object
77
                        if(item.second.type==LinkableObject::Local) {
78
                                if(it->second.obj) {
79
                                        std::ostringstream msg;
80
                                        msg<<obj->name()<<": Duplicate definition of \""<<item.first;
81
                                        msg<<"\" (previously defined in "<<it->second.obj->name()<<")";
82
                                        throw std::runtime_error(msg.str());
83
                                }
84
                                it->second.obj=obj;
85
                                it->second.rva=item.second.rva;
86
                        }
87
 
88
// Merge reference tables
89
                        for(auto const &ref: item.second.refs) it->second.refs.emplace(obj,ref.rva);
90
                }
91
        }
92
 
93
// Check that no undefined symbols remain
94
        for(auto const &item: _globalSymbolTable) {
95
                if(item.second.obj==nullptr&&!item.second.refs.empty()) {
96
                        std::ostringstream msg;
97
                        msg<<"Undefined symbol: \""<<item.first<<"\"";
98
                        auto const it=item.second.refs.begin();
99
                        msg<<" (referenced from "<<it->first->name()<<")";
100
                        throw std::runtime_error(msg.str());
101
                }
102
        }
103
}
104
 
105
void Linker::placeObjects() {
106
        auto currentBase=_base;
107
 
108
// Make entry object the first
109
        if(_objects.size()>1) {
110
                for(auto it=_objects.begin();it!=_objects.end();++it) {
111
                        if(*it==_entryObject) {
112
                                std::swap(*it,_objects[0]);
113
                                break;
114
                        }
115
                }
116
        }
117
 
118
// Set base addresses
119
        for(auto it=_objects.begin();it!=_objects.end();++it) {
120
                (*it)->setVirtualAddress(currentBase);
121
                if(it+1!=_objects.end()) (*it)->addPadding(_align);
122
                else (*it)->addPadding();
123
                currentBase+=static_cast<LinkableObject::Word>((*it)->codeSize());
124
        }
125
}
126
 
127
void Linker::relocateObject(LinkableObject *obj) {
128
        for(auto const &sym: obj->symbols()) {
129
                auto it=_globalSymbolTable.find(sym.first);
130
                assert(it!=_globalSymbolTable.end());
131
                if(it->second.refs.empty()) continue;
132
                assert(it->second.obj);
133
                auto addr=it->second.obj->virtualAddress()+it->second.rva;
134
                for(auto const &ref: sym.second.refs) {
135
                        auto offset=obj->getWord(ref.rva);
136
                        obj->replaceWord(ref.rva,addr+offset);
137
                }
138
        }
139
}
140
 
141
void Linker::writeObjects(OutputWriter &writer) {
142
        std::size_t currentSize=0;
143
// Write entry object
144
        writer.write(reinterpret_cast<const char*>(_entryObject->code()),_entryObject->codeSize());
145
        currentSize+=_entryObject->codeSize();
146
// Write other objects
147
        for(auto const &obj: _objects) {
148
                if(obj==_entryObject) continue;
149
                writer.write(reinterpret_cast<const char*>(obj->code()),obj->codeSize());
150
                currentSize+=obj->codeSize();
151
        }
152
 
153
// Pad file if requested
154
        if(_imageSize>0) {
155
                if(currentSize>_imageSize)
156
                        throw std::runtime_error("Image size exceeds the specified value");
157
                else if(currentSize<_imageSize) writer.pad(_imageSize-currentSize);
158
        }
159
}

powered by: WebSVN 2.1.0

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