1 using System;
2 using System.Collections;
3
4 namespace cmsx.object
5 {
6 public enum LinkCode : byte
7 {
8 forwardLongJump = 1u, forwardShortJump = 2u, absoluteAddrValue = 3u, farJump = 4u, farOcta = 5u, clsid = 6u, end = 7u
9 }
10
11 public const int maxLinkCodeStrLength = 17;
12
13 public string LinkCodeStr(LinkCode linkCode)
14 {
15 switch (linkCode)
16 {
17 case LinkCode.forwardLongJump: return "LINKFWDLONGJUMP";
18 case LinkCode.forwardShortJump: return "LINKFWDSHORTJMP";
19 case LinkCode.absoluteAddrValue: return "LINKABSOLUTEADDR";
20 case LinkCode.farOcta: return "LINKFAROCTA";
21 case LinkCode.clsid: return "LINKCLSID";
22 }
23 return "";
24 }
25
26 public abstract class LinkCommand
27 {
28 public nothrow LinkCommand(ObjectFile* objectFile_, ulong address_) : objectFile(objectFile_), address(address_)
29 {
30 }
31 public virtual default ~LinkCommand();
32 public virtual void Execute(ulong value, bool debug)
33 {
34 }
35 public ObjectFile* objectFile;
36 public ulong address;
37 }
38
39 public class LinkOnceCommand : LinkCommand
40 {
41 public nothrow LinkOnceCommand(ObjectFile* objectFile_) : base(objectFile_, 0u)
42 {
43 }
44 }
45
46 public class LinkAbsoluteAddressCommand : LinkCommand
47 {
48 public nothrow LinkAbsoluteAddressCommand(ObjectFile* objectFile_, ulong address_) : base(objectFile_, address_)
49 {
50 }
51 public override void Execute(ulong value, bool debug)
52 {
53 if (debug)
54 {
55 Console.Out() << objectFile->FileName() << ": LINKABSOLUTEADDR(" << ToHexString(address) << " : " << ToHexString(value) << ")" << endl();
56 }
57 byte b0 = cast<byte>(value);
58 value = value >> 8u;
59 byte b1 = cast<byte>(value);
60 value = value >> 8u;
61 byte b2 = cast<byte>(value);
62 value = value >> 8u;
63 byte b3 = cast<byte>(value);
64 value = value >> 8u;
65 byte b4 = cast<byte>(value);
66 value = value >> 8u;
67 byte b5 = cast<byte>(value);
68 value = value >> 8u;
69 byte b6 = cast<byte>(value);
70 value = value >> 8u;
71 byte b7 = cast<byte>(value);
72 value = value >> 8u;
73 ushort offset = (cast<ushort>(b7) << 8u) | cast<ushort>(b6);
74 objectFile->codeSection->EmitShortOffset(address, offset);
75 offset = (cast<ushort>(b5) << 8u) | cast<ushort>(b4);
76 objectFile->codeSection->EmitShortOffset(address + 4u, offset);
77 offset = (cast<ushort>(b3) << 8u) | cast<ushort>(b2);
78 objectFile->codeSection->EmitShortOffset(address + 8u, offset);
79 offset = (cast<ushort>(b1) << 8u) | cast<ushort>(b0);
80 objectFile->codeSection->EmitShortOffset(address + 12u, offset);
81 }
82 }
83
84 public class LinkFarOctaCommand : LinkCommand
85 {
86 public nothrow LinkFarOctaCommand(ObjectFile* objectFile_, ulong address_) : base(objectFile_, address_)
87 {
88 }
89 public override void Execute(ulong value, bool debug)
90 {
91 if (debug)
92 {
93 Console.Out() << objectFile->FileName() << ": LINKFAROCTA(" << ToHexString(address) << " : " << ToHexString(value) << ")" << endl();
94 }
95 objectFile->dataSection->EmitULong(address, value);
96 }
97 }
98
99 public class LinkClsIdCommand : LinkCommand
100 {
101 public nothrow LinkClsIdCommand(ObjectFile* objectFile_, ulong address_, ulong classId_) : base(objectFile_, address_), classId(classId_)
102 {
103 }
104 public override void Execute(ulong value, bool debug)
105 {
106 if (debug)
107 {
108 Console.Out() << objectFile->FileName() << ": LINKCLSID(" << ToHexString(address) << " : " << ToHexString(classId) << ")" << endl();
109 }
110 objectFile->dataSection->EmitULong(address, classId);
111 }
112 private ulong classId;
113 }
114
115 public class CopyRange
116 {
117 public nothrow CopyRange(Section* fromSection_, Section* toSection_, ulong startPos_, ulong length_, byte alignment_) :
118 fromSection(fromSection_), toSection(toSection_), startPos(startPos_), length(length_), alignment(alignment_)
119 {
120 }
121 public string Str() const
122 {
123 return "copy from " + fromSection->file->FileName() + " " + fromSection->name + " section to target " + toSection->file->FileName() + " " + toSection->name + " section: [" + ToHexString(startPos) + ":" + ToHexString(length) + "] align " + ToString(alignment);
124 }
125 public Section* fromSection;
126 public Section* toSection;
127 public ulong startPos;
128 public ulong length;
129 public byte alignment;
130 }
131
132 public class LinkTable
133 {
134 public nothrow LinkTable(const ClassIdMap& classIdMap_) : classIdMap(classIdMap_)
135 {
136 }
137 public void AddLinkCommand(const string& symbolName, LinkCommand* command)
138 {
139 List<LinkCommand*>& commands = linkCommandMap[symbolName];
140 commands.Add(command);
141 }
142 public void ExecuteLinkCommands(const string& symbolName, ulong value, bool debug)
143 {
144 Map<string, List<LinkCommand*>>.ConstIterator it = linkCommandMap.CFind(symbolName);
145 if (it != linkCommandMap.CEnd())
146 {
147 List<LinkCommand*>& commands = it->second;
148 if (debug)
149 {
150 Console.Out() << "executing link commands for symbol " << symbolName << " with value " << ToHexString(value) << endl();
151 }
152 for (LinkCommand* command : commands)
153 {
154 command->Execute(value, debug);
155 delete command;
156 }
157 linkCommandMap.Remove(symbolName);
158 }
159 }
160 public void AddCopyRange(const CopyRange& copyRange, bool debug)
161 {
162 if (copyRange.length == 0u)
163 {
164 return;
165 }
166 if (!copyRanges.IsEmpty())
167 {
168 CopyRange& prev = copyRanges.Back();
169 if (prev.fromSection == copyRange.fromSection && prev.toSection == copyRange.toSection && prev.startPos + prev.length == copyRange.startPos)
170 {
171 if (debug)
172 {
173 Console.Out() << "extended " << prev.Str();
174 }
175 prev.length = prev.length + copyRange.length;
176 if (debug)
177 {
178 Console.Out() << " length to " << ToHexString(prev.length) << endl();
179 }
180 return;
181 }
182 }
183 copyRanges.Add(copyRange);
184 if (debug)
185 {
186 Console.Out() << "added " << copyRange.Str() << endl();
187 }
188 }
189 public void ReportUnresolvedSymbols()
190 {
191 bool hasUnresolvedSymbols = false;
192 for (Pair<string, List<LinkCommand*>>& p : linkCommandMap)
193 {
194 for (LinkCommand* command : p.second)
195 {
196 hasUnresolvedSymbols = true;
197 Console.Error() << "unresolved external symbol '" << p.first << "' detected in file " << command->objectFile->FileName() << endl();
198 }
199 }
200 if (hasUnresolvedSymbols)
201 {
202 throw Exception("linking failed because unresolved external symbols detected");
203 }
204 }
205 public void CopyRanges(bool debug)
206 {
207 for (const CopyRange& copyRange : copyRanges)
208 {
209 ulong n = copyRange.length;
210 if (n > 0u)
211 {
212 if (debug)
213 {
214 Console.Out() << copyRange.Str() << endl();
215 }
216 Section* fromSection = copyRange.fromSection;
217 Section* toSection = copyRange.toSection;
218 ulong startPos = copyRange.startPos;
219 toSection->Align(copyRange.alignment);
220 for (ulong i = 0u; i < n; ++i;)
221 {
222 toSection->data.Add(fromSection->data[cast<long>(startPos + i)]);
223 }
224 }
225 }
226 }
227 public ulong CodeByteCount() const
228 {
229 ulong count = 0u;
230 for (const CopyRange& copyRange : copyRanges)
231 {
232 if (copyRange.fromSection is CodeSection*)
233 {
234 count = count + copyRange.length;
235 }
236 }
237 return count;
238 }
239 public ulong GetClassId(const Uuid& typeId) const
240 {
241 return classIdMap.GetClassId(typeId);
242 }
243 public void AddUsedSymbolName(const string& symbolName)
244 {
245 usedSymbolNames.Insert(symbolName);
246 }
247 public bool IsUsedSymbolName(const string& symbolName)
248 {
249 return usedSymbolNames.CFind(symbolName) != usedSymbolNames.CEnd();
250 }
251 public ~LinkTable()
252 {
253 for (Pair<string, List<LinkCommand*>>& p : linkCommandMap)
254 {
255 for (LinkCommand* command : p.second)
256 {
257 delete command;
258 }
259 }
260 }
261 public void AddUnprocessedSymbol(Symbol* symbol, Section* section, SymbolTable* symbolTable)
262 {
263 List<Pair<Symbol*, Pair<Section*, SymbolTable*>>>& unprocessedSymbolList = unprocessedSymbolLists[symbol->name];
264 unprocessedSymbolList.Add(MakePair(symbol, MakePair(section, symbolTable)));
265 }
266 public List<Pair<Symbol*, Pair<Section*, SymbolTable*>>>* GetUnprocessedSymbolList(const string& symbolName)
267 {
268 HashMap<string, List<Pair<Symbol*, Pair<Section*, SymbolTable*>>>>.ConstIterator it = unprocessedSymbolLists.CFind(symbolName);
269 if (it != unprocessedSymbolLists.CEnd())
270 {
271 return &it->second;
272 }
273 else
274 {
275 return null;
276 }
277 }
278 private Map<string, List<LinkCommand*>> linkCommandMap;
279 private List<CopyRange> copyRanges;
280 private const ClassIdMap& classIdMap;
281 private HashSet<string> usedSymbolNames;
282 private HashMap<string, List<Pair<Symbol*, Pair<Section*, SymbolTable*>>>> unprocessedSymbolLists;
283 }
284
285 public void LinkInternal(ObjectFile& objectFile)
286 {
287 UniquePtr<Section> newLinkSection(new LinkSection(&objectFile));
288 SymbolTable& symbolTable = objectFile.GetSymbolTable();
289 Section* linkSection = objectFile.linkSection;
290 #assert(linkSection != null);
291 Section* codeSection = objectFile.codeSection;
292 #assert(codeSection != null);
293 linkSection->pos = 0u;
294 int x = linkSection->GetByte();
295 while (x != -1)
296 {
297 LinkCode linkCode = cast<LinkCode>(cast<byte>(x));
298 switch (linkCode)
299 {
300 case LinkCode.forwardLongJump:
301 {
302 uint symbolIndex = linkSection->GetUInt();
303 ulong fromAddress = linkSection->GetULong();
304 Symbol* symbol = symbolTable.GetSymbol(cast<int>(symbolIndex));
305 #assert(symbol != null);
306 #assert(symbol->segment == Segment.text);
307 #assert(symbol->value.GetFlag(Value.Flag.address));
308 ulong toAddress = symbol->value.value;
309 #assert(toAddress >= fromAddress);
310 ulong offset = (toAddress - fromAddress) >> 2u;
311 if (offset >= cast<ulong>(MaxValue<ushort>()) << 8u)
312 {
313 throw Exception("error linking: forward long jump too far");
314 }
315 codeSection->EmitLongOffset(fromAddress, cast<uint>(offset));
316 break;
317 }
318 case LinkCode.forwardShortJump:
319 {
320 uint symbolIndex = linkSection->GetUInt();
321 ulong fromAddress = linkSection->GetULong();
322 Symbol* symbol = symbolTable.GetSymbol(cast<int>(symbolIndex));
323 #assert(symbol != null);
324 #assert(symbol->segment == Segment.text);
325 #assert(symbol->value.GetFlag(Value.Flag.address));
326 ulong toAddress = symbol->value.value;
327 #assert(toAddress >= fromAddress);
328 ulong offset = (toAddress - fromAddress) >> 2u;
329 if (offset >= cast<ulong>(MaxValue<ushort>()))
330 {
331 throw Exception("error linking: forward short jump too far");
332 }
333 codeSection->EmitShortOffset(fromAddress, cast<ushort>(offset));
334 break;
335 }
336 case LinkCode.absoluteAddrValue:
337 {
338 uint index = linkSection->GetUInt();
339 ulong address = linkSection->GetULong();
340 newLinkSection->EmitByte(LinkCode.absoluteAddrValue);
341 newLinkSection->EmitUInt(cast<uint>(index));
342 newLinkSection->EmitULong(address);
343 break;
344 }
345 case LinkCode.farOcta:
346 {
347 uint index = linkSection->GetUInt();
348 ulong address = linkSection->GetULong();
349 newLinkSection->EmitByte(LinkCode.farOcta);
350 newLinkSection->EmitUInt(cast<uint>(index));
351 newLinkSection->EmitULong(address);
352 break;
353 }
354 case LinkCode.clsid:
355 {
356 ulong address = linkSection->GetULong();
357 ulong typeId1 = linkSection->GetULong();
358 ulong typeId2 = linkSection->GetULong();
359 newLinkSection->EmitByte(LinkCode.clsid);
360 newLinkSection->EmitULong(address);
361 newLinkSection->EmitULong(typeId1);
362 newLinkSection->EmitULong(typeId2);
363 break;
364 }
365 }
366 x = linkSection->GetByte();
367 }
368 objectFile.ReplaceLinkSection(newLinkSection);
369 }
370
371 public void ProcessSymbols(LinkTable& linkTable, ExecutableFile& executable, ObjectFile* objectFile, bool removeUnusedCode, bool debug)
372 {
373 if (debug)
374 {
375 Console.Out() << "begin processing symbols" << endl();
376 }
377 SymbolTable& objectFileSymbolTable = objectFile->GetSymbolTable();
378 Section* codeSection = objectFile->codeSection;
379 codeSection->copyStartPos = 0u;
380 codeSection->copyTargetSection = executable.codeSection;
381 codeSection->removeOffset = 0u;
382 ulong codeSectionLength = codeSection->dataLength;
383 Section* dataSection = objectFile->dataSection;
384 dataSection->copyTargetSection = executable.dataSection;
385 dataSection->copyStartPos = 0u;
386 dataSection->removeOffset = 0u;
387 ulong dataSectionLength = dataSection->dataLength;
388 SymbolTable& executableSymbolTable = executable.GetSymbolTable();
389 List<Symbol*> linkSymbols;
390 for (const UniquePtr<Symbol>& symbol : objectFileSymbolTable.Symbols())
391 {
392 if (symbol->linkage == Linkage.internal_)
393 {
394 if (symbol->value.GetFlag(Value.Flag.address) && (symbol->segment == Segment.text || symbol->segment == Segment.data))
395 {
396 bool process = true;
397 if (symbol->parentIndex != -1)
398 {
399 Symbol* parentSymbol = objectFileSymbolTable.GetSymbol(symbol->parentIndex);
400 if (parentSymbol != null && (parentSymbol->linkage == Linkage.remove || removeUnusedCode && !parentSymbol->value.GetFlag(Value.Flag.used)))
401 {
402 process = false;
403 }
404 }
405 if (process)
406 {
407 symbol->start = symbol->section->baseAddress + symbol->value.value - symbol->section->removeOffset;
408 Symbol* executableSymbol = symbol->Clone();
409 #assert(executableSymbol->section != null);
410 if (executableSymbol->section is DataSection*)
411 {
412 executable.dataSection->AddSymbol(executableSymbol);
413 }
414 executableSymbolTable.AddInternalSymbol(executableSymbol, true);
415 }
416 }
417 }
418 else if (symbol->linkage == Linkage.external || symbol->linkage == Linkage.undefined)
419 {
420 if (debug)
421 {
422 Console.Out() << "begin processing " << LinkageStr(symbol->linkage) << " symbol " << symbol->name << " : " << ToHexString(symbol->value.value) << ":" << ToHexString(symbol->length) << ":" << ToString(symbol->alignment) << endl();
423 }
424 if (symbol->value.GetFlag(Value.Flag.address) && (symbol->segment == Segment.text || symbol->segment == Segment.data))
425 {
426 if (symbol->value.GetFlag(Value.Flag.definition))
427 {
428 Symbol* prevSymbol = executableSymbolTable.GetSymbol(symbol->name);
429 if (prevSymbol != null)
430 {
431 #assert(prevSymbol->section != null);
432 #assert(symbol->section != null);
433 throw Exception("Duplicate external symbol '" + symbol->name +
434 "'. Original defined in " + prevSymbol->section->name + " section of file " + prevSymbol->section->file->FileName() +
435 ". Duplicate detected in " + symbol->section->name + " section of file " + symbol->section->file->FileName() + ".");
436 }
437 else
438 {
439 if (symbol->value.GetFlag(Value.Flag.used) || !removeUnusedCode)
440 {
441 symbol->start = symbol->section->baseAddress + symbol->value.value - symbol->section->removeOffset;
442 Symbol* executableSymbol = symbol->Clone();
443 executableSymbol->linkage = Linkage.external;
444 #assert(executableSymbol->section != null);
445 if (executableSymbol->section is DataSection*)
446 {
447 executable.dataSection->AddSymbol(executableSymbol);
448 }
449 executableSymbolTable.AddSymbol(executableSymbol);
450 linkTable.ExecuteLinkCommands(symbol->name, symbol->start, debug);
451 linkTable.AddCopyRange(CopyRange(symbol->section, symbol->section->copyTargetSection, symbol->value.value, symbol->length, symbol->alignment), debug);
452 symbol->section->copyStartPos = symbol->value.value + symbol->length;
453 linkSymbols.Add(symbol.Get());
454 }
455 else
456 {
457 if (debug)
458 {
459 Console.Out() << "setting unused " << LinkageStr(symbol->linkage) << " symbol " << symbol->name << " linkage to remove" << endl();
460 }
461 symbol->linkage = Linkage.remove;
462 symbol->section->copyStartPos = symbol->value.value + symbol->length;
463 symbol->section->removeOffset = symbol->section->removeOffset + symbol->length;
464 symbol->section->dataLength = symbol->section->dataLength - symbol->length;
465 }
466 }
467 }
468 }
469 else if (symbol->value.flags == Value.Flag.undefined)
470 {
471 Symbol* prevSymbol = executableSymbolTable.GetSymbol(symbol->name);
472 if (prevSymbol != null)
473 {
474 symbol->start = prevSymbol->start;
475 symbol->linkage = Linkage.external;
476 if (debug)
477 {
478 Console.Out() << "define symbol " << symbol->name << " start " << ToHexString(symbol->start) << endl();
479 }
480 }
481 }
482 if (debug)
483 {
484 Console.Out() << "end processing " << LinkageStr(symbol->linkage) << " symbol " << symbol->name << " : " << ToHexString(symbol->start) << " : " << ToHexString(symbol->value.value) << ":" << ToHexString(symbol->length) << ":" << ToString(symbol->alignment) << endl();
485 }
486 }
487 else if (symbol->linkage == Linkage.once)
488 {
489 if (debug)
490 {
491 Console.Out() << "begin processing " << LinkageStr(symbol->linkage) << " symbol " << symbol->name << " : " << ToHexString(symbol->value.value) << ":" << ToHexString(symbol->length) << ":" << ToString(symbol->alignment) << endl();
492 }
493 if (symbol->value.GetFlag(Value.Flag.address) && (symbol->segment == Segment.text || symbol->segment == Segment.data))
494 {
495 if (symbol->value.GetFlag(Value.Flag.definition))
496 {
497 Symbol* prevSymbol = executableSymbolTable.GetSymbol(symbol->name);
498 if (prevSymbol == null)
499 {
500 if (symbol->value.GetFlag(Value.Flag.used) || !removeUnusedCode)
501 {
502 symbol->start = symbol->section->baseAddress + symbol->value.value - symbol->section->removeOffset;
503 Symbol* executableSymbol = symbol->Clone();
504 #assert(executableSymbol->section != null);
505 if (executableSymbol->section is DataSection*)
506 {
507 executable.dataSection->AddSymbol(executableSymbol);
508 }
509 executableSymbolTable.AddSymbol(executableSymbol);
510 linkTable.ExecuteLinkCommands(symbol->name, symbol->start, debug);
511 linkTable.AddCopyRange(CopyRange(symbol->section, symbol->section->copyTargetSection, symbol->value.value, symbol->length, symbol->alignment), debug);
512 symbol->section->copyStartPos = symbol->value.value + symbol->length;
513 linkSymbols.Add(symbol.Get());
514 }
515 else
516 {
517 if (debug)
518 {
519 Console.Out() << "setting unused " << LinkageStr(symbol->linkage) << " symbol " << symbol->name << " linkage to remove" << endl();
520 }
521 symbol->linkage = Linkage.remove;
522 symbol->section->copyStartPos = symbol->value.value + symbol->length;
523 symbol->section->removeOffset = symbol->section->removeOffset + symbol->length;
524 symbol->section->dataLength = symbol->section->dataLength - symbol->length;
525 }
526 }
527 else
528 {
529 if (debug)
530 {
531 Console.Out() << "setting " << LinkageStr(symbol->linkage) << " symbol " << symbol->name << " linkage to remove" << endl();
532 }
533 symbol->linkage = Linkage.remove;
534 symbol->section->copyStartPos = symbol->value.value + symbol->length;
535 symbol->section->removeOffset = symbol->section->removeOffset + symbol->length;
536 symbol->section->dataLength = symbol->section->dataLength - symbol->length;
537 }
538 }
539 }
540 if (debug)
541 {
542 Console.Out() << "end processing " << LinkageStr(symbol->linkage) << " symbol " << symbol->name << " : " << ToHexString(symbol->start) << " : " << ToHexString(symbol->value.value) << ":" << ToHexString(symbol->length) << ":" << ToString(symbol->alignment) << endl();
543 }
544 }
545 }
546 if (debug)
547 {
548 Console.Out() << "end processing symbols" << endl();
549 }
550 for (Symbol* linkSymbol : linkSymbols)
551 {
552 ProcessLinkSection(linkTable, executable, objectFile, linkSymbol, debug);
553 }
554 }
555
556 public void ProcessLinkSection(LinkTable& linkTable, ExecutableFile& executable, ObjectFile* objectFile, Symbol* forSymbol, bool debug)
557 {
558 if (debug)
559 {
560 Console.Out() << "begin processing link section for symbol " << forSymbol->name << " [" << forSymbol->linkStart << ":" << forSymbol->linkEnd << "]" << endl();
561 }
562 SymbolTable& executableSymbolTable = executable.GetSymbolTable();
563 Section* linkSection = objectFile->linkSection;
564 long prevPos = linkSection->pos;
565 linkSection->pos = cast<long>(forSymbol->linkStart);
566 int x = linkSection->GetByte();
567 while (x != -1 && linkSection->pos < cast<long>(forSymbol->linkEnd))
568 {
569 LinkCode linkCode = cast<LinkCode>(cast<byte>(x));
570 Symbol* symbol = null;
571 UniquePtr<LinkCommand> linkCommand;
572 switch (linkCode)
573 {
574 case LinkCode.absoluteAddrValue:
575 {
576 uint index = linkSection->GetUInt();
577 ulong address = linkSection->GetULong();
578 symbol = objectFile->GetSymbolTable().GetSymbol(cast<int>(index));
579 bool linkageIsRemove = false;
580 if (symbol->linkage == Linkage.remove)
581 {
582 linkageIsRemove = true;
583 }
584 if (symbol->value.flags == Value.Flag.undefined || linkageIsRemove)
585 {
586 Symbol* executableSymbol = executableSymbolTable.GetSymbol(symbol->name);
587 if (executableSymbol != null)
588 {
589 symbol = executableSymbol;
590 }
591 }
592 linkCommand.Reset(new LinkAbsoluteAddressCommand(objectFile, address));
593 break;
594 }
595 case LinkCode.farOcta:
596 {
597 uint index = linkSection->GetUInt();
598 ulong address = linkSection->GetULong();
599 symbol = objectFile->GetSymbolTable().GetSymbol(cast<int>(index));
600 bool linkageIsRemove = false;
601 if (symbol->linkage == Linkage.remove)
602 {
603 linkageIsRemove = true;
604 }
605 if (symbol->value.flags == Value.Flag.undefined || linkageIsRemove)
606 {
607 Symbol* executableSymbol = executableSymbolTable.GetSymbol(symbol->name);
608 if (executableSymbol != null)
609 {
610 symbol = executableSymbol;
611 }
612 }
613 linkCommand.Reset(new LinkFarOctaCommand(objectFile, address));
614 break;
615 }
616 case LinkCode.clsid:
617 {
618 ulong address = linkSection->GetULong();
619 ulong typeId1 = linkSection->GetULong();
620 ulong typeId2 = linkSection->GetULong();
621 Uuid typeId(typeId1, typeId2);
622 linkCommand.Reset(new LinkClsIdCommand(objectFile, address, linkTable.GetClassId(typeId)));
623 linkCommand->Execute(0u, debug);
624 linkCommand.Reset();
625 break;
626 }
627 default:
628 {
629 symbol = null;
630 linkCommand.Reset();
631 break;
632 }
633 }
634 if (!linkCommand.IsNull() && symbol != null)
635 {
636 if (symbol->value.GetFlag(Value.Flag.address))
637 {
638 linkCommand->Execute(symbol->start, debug);
639 }
640 else if (symbol->value.flags == Value.Flag.undefined)
641 {
642 linkTable.AddLinkCommand(symbol->name, linkCommand.Release());
643 }
644 }
645 x = linkSection->GetByte();
646 }
647 if (debug)
648 {
649 Console.Out() << "end processing link section for symbol " << forSymbol->name << " [" << forSymbol->linkStart << ":" << forSymbol->linkEnd << "]" << endl();
650 }
651 }
652
653 public void LinkObjectFile(LinkTable& linkTable, ExecutableFile& executable, ObjectFile* objectFile, Section*& prevCodeSection, Section*& prevDataSection, bool removeUnusedCode, bool debug)
654 {
655 if (debug)
656 {
657 Console.Out() << "begin linking " << objectFile->FileName() << endl();
658 }
659 SymbolTable& executableSymbolTable = executable.GetSymbolTable();
660 Section* codeSection = objectFile->codeSection;
661 if (prevCodeSection == null)
662 {
663 codeSection->baseAddress = cmsx.machine.textSegmentBaseAddress + 4096u;
664 executable.codeSection->baseAddress = codeSection->baseAddress;
665 if (debug)
666 {
667 Console.Out() << "setting code section base address to " << ToHexString(codeSection->baseAddress) << endl();
668 }
669 }
670 else
671 {
672 codeSection->baseAddress = prevCodeSection->baseAddress + prevCodeSection->dataLength;
673 if (debug)
674 {
675 Console.Out() << "setting code section base address to " << ToHexString(codeSection->baseAddress) << endl();
676 }
677 }
678 prevCodeSection = codeSection;
679 Section* dataSection = objectFile->dataSection;
680 if (prevDataSection == null)
681 {
682 dataSection->baseAddress = cmsx.machine.dataSegmentBaseAddress;
683 executable.dataSection->baseAddress = dataSection->baseAddress;
684 if (debug)
685 {
686 Console.Out() << "setting data section base address to " << ToHexString(dataSection->baseAddress) << endl();
687 }
688 }
689 else
690 {
691 dataSection->baseAddress = prevDataSection->baseAddress + prevDataSection->dataLength;
692 if (debug)
693 {
694 Console.Out() << "setting data section base address to " << ToHexString(dataSection->baseAddress) << endl();
695 }
696 }
697 prevDataSection = dataSection;
698 ProcessSymbols(linkTable, executable, objectFile, removeUnusedCode, debug);
699 if (debug)
700 {
701 Console.Out() << "end linking " << objectFile->FileName() << endl();
702 }
703 }
704
705 public void ProcessUsedSymbol(Symbol* symbol, SymbolTable& symbolTable, LinkTable& linkTable, Section* linkSection, bool debug)
706 {
707 if (symbol->value.GetFlag(Value.Flag.used)) return;
708 if (debug)
709 {
710 Console.Out() << "begin processing used symbol " << symbol->name << endl();
711 }
712 symbol->value.SetUsed();
713 if (symbol->linkStart != -1 && symbol->linkEnd != -1)
714 {
715 long prevPos = linkSection->pos;
716 linkSection->pos = cast<long>(symbol->linkStart);
717 int x = linkSection->GetByte();
718 while (x != -1 && linkSection->pos < cast<long>(symbol->linkEnd))
719 {
720 LinkCode linkCode = cast<LinkCode>(cast<byte>(x));
721 Symbol* s = null;
722 switch (linkCode)
723 {
724 case LinkCode.absoluteAddrValue:
725 {
726 uint index = linkSection->GetUInt();
727 ulong address = linkSection->GetULong();
728 s = symbolTable.GetSymbol(cast<int>(index));
729 break;
730 }
731 case LinkCode.farOcta:
732 {
733 uint index = linkSection->GetUInt();
734 ulong address = linkSection->GetULong();
735 s = symbolTable.GetSymbol(cast<int>(index));
736 break;
737 }
738 case LinkCode.clsid:
739 {
740 ulong address = linkSection->GetULong();
741 ulong typeId1 = linkSection->GetULong();
742 ulong typeId2 = linkSection->GetULong();
743 break;
744 }
745 }
746 if (s != null)
747 {
748 if (debug)
749 {
750 Console.Out() << "adding symbol " + s->name + " to used symbol names" << endl();
751 }
752 linkTable.AddUsedSymbolName(s->name);
753 List<Pair<Symbol*, Pair<Section*, SymbolTable*>>>* unprocessedSymbols = linkTable.GetUnprocessedSymbolList(s->name);
754 if (unprocessedSymbols != null)
755 {
756 List<Pair<Symbol*, Pair<Section*, SymbolTable*>>> symbols;
757 Swap(*unprocessedSymbols, symbols);
758 for (const Pair<Symbol*, Pair<Section*, SymbolTable*>>& p : symbols)
759 {
760 Symbol* unprocessedSymbol = p.first;
761 Section* section = p.second.first;
762 SymbolTable* stab = p.second.second;
763 ProcessUsedSymbol(unprocessedSymbol, *stab, linkTable, section, debug);
764 }
765 }
766 }
767 x = linkSection->GetByte();
768 }
769 linkSection->pos = prevPos;
770 }
771 else
772 {
773 throw Exception("link start and end not set");
774 }
775 if (debug)
776 {
777 Console.Out() << "end processing used symbol " << symbol->name << endl();
778 }
779 }
780
781 public void MarkUsedSymbols(LinkTable& linkTable, ObjectFile* objectFile, bool debug)
782 {
783 if (debug)
784 {
785 Console.Out() << "begin marking used symbols for object file " << objectFile->FileName() << endl();
786 }
787 SymbolTable& objectFileSymbolTable = objectFile->GetSymbolTable();
788 for (const UniquePtr<Symbol>& symbol : objectFileSymbolTable.Symbols())
789 {
790 if (symbol->value.GetFlag(Value.Flag.definition) && symbol->value.GetFlag(Value.Flag.address) && (symbol->linkage == Linkage.external || symbol->linkage == Linkage.once) &&
791 (symbol->segment == Segment.text || symbol->segment == Segment.data))
792 {
793 if (linkTable.IsUsedSymbolName(symbol->name))
794 {
795 ProcessUsedSymbol(symbol.Get(), objectFile->GetSymbolTable(), linkTable, objectFile->linkSection, debug);
796 }
797 else
798 {
799 linkTable.AddUnprocessedSymbol(symbol.Get(), objectFile->linkSection, &objectFile->GetSymbolTable());
800 }
801 }
802 }
803 if (debug)
804 {
805 Console.Out() << "end marking used symbols for object file " << objectFile->FileName() << endl();
806 }
807 }
808
809 public List<DispatchTableEntry> InsertIntoDispatchTable(const List<DispatchTableEntry>& dispatchTable, const DispatchTableEntry& entry, Section* dataSection)
810 {
811 if (entry.dispatchBlock is CleanupDispatchBlock*)
812 {
813 CleanupDispatchBlock* cleanupDispatchBlock = cast<CleanupDispatchBlock*>(entry.dispatchBlock);
814 TryBlock* parentTryBlock = cleanupDispatchBlock->tryBlock;
815 if (parentTryBlock != null)
816 {
817 ulong parentTableAddress = parentTryBlock->exceptionBlockTableAddress;
818 long prevPos = dataSection->pos;
819 dataSection->pos = cast<long>(entry.exceptionBlockTableAddress + 16u);
820 dataSection->EmitULong(parentTableAddress);
821 dataSection->pos = prevPos;
822 }
823 }
824 bool inserted = false;
825 List<DispatchTableEntry> newDispatchTable;
826 for (const DispatchTableEntry& prevEntry : dispatchTable)
827 {
828 if (entry.offset < prevEntry.offset)
829 {
830 newDispatchTable.Add(entry);
831 newDispatchTable.Add(prevEntry);
832 inserted = true;
833 }
834 else if (entry.offset >= prevEntry.offset + prevEntry.length)
835 {
836 newDispatchTable.Add(prevEntry);
837 }
838 else if (entry.offset >= prevEntry.offset && entry.offset < prevEntry.offset + prevEntry.length)
839 {
840 if (entry.offset + entry.length <= prevEntry.offset + prevEntry.length)
841 {
842 DispatchTableEntry startEntry(prevEntry.offset, entry.offset - prevEntry.offset, prevEntry.exceptionBlockTableAddress, prevEntry.dispatchBlock);
843 if (startEntry.length > 0)
844 {
845 newDispatchTable.Add(startEntry);
846 }
847 newDispatchTable.Add(entry);
848 inserted = true;
849 DispatchTableEntry endEntry(entry.offset + entry.length, (prevEntry.offset + prevEntry.length) - (entry.offset + entry.length), prevEntry.exceptionBlockTableAddress,
850 prevEntry.dispatchBlock);
851 if (endEntry.length > 0)
852 {
853 newDispatchTable.Add(endEntry);
854 }
855 }
856 else
857 {
858 throw Exception("invalid dispatch table entry (not contained by the parent entry): previous entry offset: " + ToString(prevEntry.offset) +
859 ", previous entry length: " + ToString(prevEntry.length) + ", entry offset: " + ToString(entry.offset) + ", entry length: " + ToString(entry.length));
860 }
861 }
862 else
863 {
864 newDispatchTable.Add(prevEntry);
865 }
866 }
867 if (!inserted)
868 {
869 newDispatchTable.Add(entry);
870 }
871 return newDispatchTable;
872 }
873
874 public ulong MakeExceptionTable(ExecutableFile& executable, const FunctionExceptionData& functionExceptionData)
875 {
876 try
877 {
878 Section* executableDataSection = executable.dataSection;
879 executableDataSection->Align(8u);
880 List<DispatchTableEntry> dispatchTable;
881 for (TryBlock& tryBlock : functionExceptionData.tryBlocks)
882 {
883 if (tryBlock.length > 0)
884 {
885 ulong exceptionBlockTableAddress = 0u;
886 for (const HandlerBlock& handlerBlock : tryBlock.handlerBlocks)
887 {
888 if (exceptionBlockTableAddress == 0u)
889 {
890 exceptionBlockTableAddress = executableDataSection->Address();
891 tryBlock.exceptionBlockTableAddress = exceptionBlockTableAddress;
892 }
893 executableDataSection->EmitULong(handlerBlock.discriminator);
894 executableDataSection->EmitULong(handlerBlock.catchedClassId);
895 executableDataSection->EmitULong(handlerBlock.handlerAddress);
896 }
897 executableDataSection->EmitULong(endBlockDiscriminator);
898 DispatchTableEntry entry(tryBlock.offset, tryBlock.length, exceptionBlockTableAddress, &tryBlock);
899 dispatchTable = InsertIntoDispatchTable(dispatchTable, entry, executableDataSection);
900 }
901 }
902 for (const CleanupDispatchBlock& cleanupDispatchBlock : functionExceptionData.cleanupDispatchBlocks)
903 {
904 if (cleanupDispatchBlock.length > 0)
905 {
906 ulong exceptionBlockTableAddress = executableDataSection->Address();
907 executableDataSection->EmitULong(cleanupDispatchBlock.cleanupBlock.discriminator);
908 executableDataSection->EmitULong(cleanupDispatchBlock.cleanupBlock.cleanupAddress);
909 executableDataSection->EmitULong(cleanupDispatchBlock.cleanupBlock.parentTableAddress);
910 executableDataSection->EmitULong(endBlockDiscriminator);
911 DispatchTableEntry entry(cleanupDispatchBlock.offset, cleanupDispatchBlock.length, exceptionBlockTableAddress, &cleanupDispatchBlock);
912 dispatchTable = InsertIntoDispatchTable(dispatchTable, entry, executableDataSection);
913 }
914 }
915 executableDataSection->Align(8u);
916 ulong exceptionTableAddress = executableDataSection->Address();
917 executableDataSection->EmitUInt(functionExceptionData.frameSize);
918 executableDataSection->EmitUInt(cast<uint>(dispatchTable.Count()));
919 for (long i = 0; i < dispatchTable.Count(); ++i;)
920 {
921 const DispatchTableEntry& entry = dispatchTable[i];
922 executableDataSection->EmitUInt(entry.offset);
923 executableDataSection->EmitUInt(entry.length);
924 executableDataSection->EmitULong(entry.exceptionBlockTableAddress);
925 }
926 return exceptionTableAddress;
927 }
928 catch (const Exception& ex)
929 {
930 throw Exception(ex.Message() + " (function=" + functionExceptionData.functionName + ")");
931 }
932 return 0u;
933 }
934
935 public void ProcessDebugSection(ExecutableFile& executable, ObjectFile* objectFile, HashMap<string, ulong>& stringAddressMap, List<FunctionTableEntry>& functionTable,
936 HashSet<ulong>& functionAddressSet, const ClassIdMap& classIdMap, bool debug)
937 {
938 if (debug)
939 {
940 Console.Out() << "begin processing debug section of " << objectFile->FileName() << endl();
941 }
942 Section* debugSection = objectFile->debugSection;
943 Section* executableDataSection = executable.dataSection;
944 HashMap<uint, ulong> sourceFileIdAddressMap;
945 HashMap<string, LineNumberTableLimits> lineNumberTableMap;
946 HashMap<string, ulong> exceptionTableAddressMap;
947 FunctionExceptionData functionExceptionData;
948 bool processFunc = false;
949 if (debugSection != null)
950 {
951 int x = debugSection->GetByte();
952 while (x != -1)
953 {
954 DebugRecordCode debugRecordCode = cast<DebugRecordCode>(cast<byte>(x));
955 if (debugRecordCode == DebugRecordCode.end)
956 {
957 break;
958 }
959 if (debugRecordCode == DebugRecordCode.fileInfo)
960 {
961 string sourceFileNameName = debugSection->GetString();
962 uint sourceFileNameId = debugSection->GetUInt();
963 HashMap<string, ulong>.ConstIterator it = stringAddressMap.CFind(sourceFileNameName);
964 ulong sourceFileNameAddress = 0u;
965 if (it == stringAddressMap.CEnd())
966 {
967 sourceFileNameAddress = executableDataSection->Address();
968 executableDataSection->EmitString(sourceFileNameName);
969 stringAddressMap[sourceFileNameName] = sourceFileNameAddress;
970 }
971 else
972 {
973 sourceFileNameAddress = it->second;
974 }
975 sourceFileIdAddressMap[sourceFileNameId] = sourceFileNameAddress;
976 }
977 else if (debugRecordCode == DebugRecordCode.functionInfo)
978 {
979 uint functionSymbolIndex = debugSection->GetUInt();
980 string functionFullName = debugSection->GetString();
981 uint sourceFileNameId = debugSection->GetUInt();
982 uint frameSize = debugSection->GetUInt();
983 HashMap<uint, ulong>.ConstIterator sit = sourceFileIdAddressMap.CFind(sourceFileNameId);
984 ulong sourceFileNameAddress = 0u;
985 if (sit != sourceFileIdAddressMap.CEnd())
986 {
987 sourceFileNameAddress = sit->second;
988 }
989 else
990 {
991 throw Exception("source file name address not found");
992 }
993 Symbol* functionSymbol = objectFile->GetSymbolTable().GetSymbol(cast<int>(functionSymbolIndex));
994 if (functionSymbol != null)
995 {
996 Symbol* finalFunctionSymbol = executable.GetSymbolTable().GetSymbol(functionSymbol->name);
997 if (finalFunctionSymbol != null)
998 {
999 if (functionAddressSet.CFind(finalFunctionSymbol->start) == functionAddressSet.CEnd())
1000 {
1001 functionAddressSet.Insert(finalFunctionSymbol->start);
1002 HashMap<string, ulong>.ConstIterator it1 = stringAddressMap.CFind(finalFunctionSymbol->name);
1003 ulong mangledNameAddress = 0u;
1004 if (it1 == stringAddressMap.CEnd())
1005 {
1006 mangledNameAddress = executableDataSection->Address();
1007 executableDataSection->EmitString(finalFunctionSymbol->name);
1008 stringAddressMap[finalFunctionSymbol->name] = mangledNameAddress;
1009 }
1010 else
1011 {
1012 mangledNameAddress = it1->second;
1013 }
1014 HashMap<string, ulong>.ConstIterator it2 = stringAddressMap.CFind(functionFullName);
1015 ulong fullNameAddress = 0u;
1016 if (it2 == stringAddressMap.CEnd())
1017 {
1018 fullNameAddress = executableDataSection->Address();
1019 executableDataSection->EmitString(functionFullName);
1020 stringAddressMap[functionFullName] = fullNameAddress;
1021 }
1022 else
1023 {
1024 fullNameAddress = it2->second;
1025 }
1026 ulong exceptionTableAddress = 0u;
1027 HashMap<string, ulong>.ConstIterator it3 = exceptionTableAddressMap.CFind(functionSymbol->name);
1028 if (it3 != exceptionTableAddressMap.CEnd())
1029 {
1030 exceptionTableAddress = it3->second;
1031 executable.dataSection->EmitUInt(exceptionTableAddress, frameSize);
1032 }
1033 LineNumberTableLimits& lineNumberTable = lineNumberTableMap[functionSymbol->name];
1034 FunctionTableEntry entry(finalFunctionSymbol->start, finalFunctionSymbol->length, mangledNameAddress, fullNameAddress, sourceFileNameAddress,
1035 lineNumberTable.startAddress, lineNumberTable.endAddress, exceptionTableAddress);
1036 functionTable.Add(entry);
1037 }
1038 }
1039 }
1040 }
1041 else if (debugRecordCode == DebugRecordCode.startFunc)
1042 {
1043 uint functionSymbolIndex = debugSection->GetUInt();
1044 Symbol* functionSymbol = objectFile->GetSymbolTable().GetSymbol(cast<int>(functionSymbolIndex));
1045 if (functionSymbol->linkage == Linkage.remove)
1046 {
1047 processFunc = false;
1048 }
1049 else
1050 {
1051 processFunc = true;
1052 executableDataSection->Align(4u);
1053 LineNumberTableLimits lineNumberTable;
1054 lineNumberTable.startAddress = executableDataSection->Address();
1055 lineNumberTableMap[functionSymbol->name] = lineNumberTable;
1056 functionExceptionData = FunctionExceptionData();
1057 functionExceptionData.functionName = functionSymbol->name;
1058 Symbol* finalFunctionSymbol = executable.GetSymbolTable().GetSymbol(functionSymbol->name);
1059 }
1060 }
1061 else if (debugRecordCode == DebugRecordCode.endFunc)
1062 {
1063 uint functionSymbolIndex = debugSection->GetUInt();
1064 if (processFunc)
1065 {
1066 Symbol* functionSymbol = objectFile->GetSymbolTable().GetSymbol(cast<int>(functionSymbolIndex));
1067 LineNumberTableLimits& lineNumberTable = lineNumberTableMap[functionSymbol->name];
1068 lineNumberTable.endAddress = executableDataSection->Address();
1069 if (!functionExceptionData.IsEmpty())
1070 {
1071 exceptionTableAddressMap[functionSymbol->name] = MakeExceptionTable(executable, functionExceptionData);
1072 functionExceptionData = FunctionExceptionData();
1073 }
1074 }
1075 }
1076 else if (debugRecordCode == DebugRecordCode.lineInfo)
1077 {
1078 uint offset = debugSection->GetUInt();
1079 uint lineNumber = debugSection->GetUInt();
1080 if (processFunc)
1081 {
1082 executableDataSection->EmitUInt(offset);
1083 executableDataSection->EmitUInt(lineNumber);
1084 }
1085 }
1086 else if (debugRecordCode == DebugRecordCode.beginTry)
1087 {
1088 uint tryBlockId = debugSection->GetUInt();
1089 uint parentTryBlockId = debugSection->GetUInt();
1090 uint offset = debugSection->GetUInt();
1091 if (processFunc)
1092 {
1093 TryBlock tryBlock(tryBlockId, parentTryBlockId, offset);
1094 functionExceptionData.tryBlocks.Add(tryBlock);
1095 }
1096 }
1097 else if (debugRecordCode == DebugRecordCode.endTry)
1098 {
1099 uint tryBlockId = debugSection->GetUInt();
1100 uint offset = debugSection->GetUInt();
1101 if (processFunc)
1102 {
1103 TryBlock* tryBlock = functionExceptionData.GetTryBlock(tryBlockId);
1104 if (tryBlock != null)
1105 {
1106 tryBlock->length = offset - tryBlock->offset;
1107 }
1108 else
1109 {
1110 throw Exception("try block id " + ToString(tryBlockId) + " not found");
1111 }
1112 }
1113 }
1114 else if (debugRecordCode == DebugRecordCode.catch_)
1115 {
1116 uint catchBlockId = debugSection->GetUInt();
1117 uint tryBlockId = debugSection->GetUInt();
1118 ulong catchedTypeId1 = debugSection->GetULong();
1119 ulong catchedTypeId2 = debugSection->GetULong();
1120 Uuid catchedTypeId(catchedTypeId1, catchedTypeId2);
1121 ulong catchedClassId = classIdMap.GetClassId(catchedTypeId);
1122 if (processFunc)
1123 {
1124 string catchBlockSymbolName = functionExceptionData.functionName;
1125 catchBlockSymbolName.Append('@').Append(ToString(catchBlockId));
1126 Symbol* handlerAddessSymbol = executable.GetSymbolTable().GetInternalSymbol(catchBlockSymbolName);
1127 if (handlerAddessSymbol != null)
1128 {
1129 ulong handlerAddress = handlerAddessSymbol->start;
1130 TryBlock* tryBlock = functionExceptionData.GetTryBlock(tryBlockId);
1131 if (tryBlock != null)
1132 {
1133 HandlerBlock handlerBlock(catchedClassId, handlerAddress);
1134 tryBlock->handlerBlocks.Add(handlerBlock);
1135 }
1136 else
1137 {
1138 throw Exception("try block id " + ToString(tryBlockId) + " not found (function=" + functionExceptionData.functionName + ")");
1139 }
1140 }
1141 else
1142 {
1143 throw Exception("handler address for symbol '" + catchBlockSymbolName + "' not found from the symbol table of the executable (function=" +
1144 functionExceptionData.functionName + ")");
1145 }
1146 }
1147 }
1148 else if (debugRecordCode == DebugRecordCode.beginCleanup)
1149 {
1150 uint cleanupBlockId = debugSection->GetUInt();
1151 uint tryBlockId = debugSection->GetUInt();
1152 uint offset = debugSection->GetUInt();
1153 if (processFunc)
1154 {
1155 TryBlock* tryBlock = null;
1156 if (cast<int>(tryBlockId) != -1)
1157 {
1158 tryBlock = functionExceptionData.GetTryBlock(tryBlockId);
1159 if (tryBlock == null)
1160 {
1161 throw Exception("try block id " + ToString(tryBlockId) + " not found from the function exception data (function=" + functionExceptionData.functionName + ")");
1162 }
1163 }
1164 CleanupDispatchBlock cleanupDispatchBlock(cleanupBlockId, tryBlock, offset);
1165 string cleanupBlockSymbolName = functionExceptionData.functionName;
1166 cleanupBlockSymbolName.Append('@').Append(ToString(cleanupBlockId));
1167 Symbol* cleanupAddessSymbol = executable.GetSymbolTable().GetInternalSymbol(cleanupBlockSymbolName);
1168 if (cleanupAddessSymbol != null)
1169 {
1170 ulong cleanupAddess = cleanupAddessSymbol->start;
1171 CleanupBlock cleanupBlock(cleanupAddess, 0u);
1172 cleanupDispatchBlock.cleanupBlock = cleanupBlock;
1173 }
1174 else
1175 {
1176 throw Exception("cleanup address for symbol '" + cleanupBlockSymbolName + "' not found from the symbol table of the executable (function=" + functionExceptionData.functionName + ")");
1177 }
1178 functionExceptionData.cleanupDispatchBlocks.Add(cleanupDispatchBlock);
1179 }
1180 }
1181 else if (debugRecordCode == DebugRecordCode.endCleanup)
1182 {
1183 uint cleanupBlockId = debugSection->GetUInt();
1184 uint offset = debugSection->GetUInt();
1185 if (processFunc)
1186 {
1187 CleanupDispatchBlock* cleanupDispatchBlock = functionExceptionData.GetOpenCleanupDispatchBlock(cleanupBlockId);
1188 if (cleanupDispatchBlock != null)
1189 {
1190 cleanupDispatchBlock->length = offset - cleanupDispatchBlock->offset;
1191 }
1192 else
1193 {
1194 throw Exception("cleanup block id " + ToString(cleanupBlockId) + " not found");
1195 }
1196 }
1197 }
1198 else
1199 {
1200 throw Exception("unknown debug record in object file '" + objectFile->FileName() + "'");
1201 }
1202 x = debugSection->GetByte();
1203 }
1204 }
1205 if (debug)
1206 {
1207 Console.Out() << "end processing debug section of " << objectFile->FileName() << endl();
1208 }
1209 }
1210
1211 public void MakeFuctionTable(ExecutableFile& executable, List<UniquePtr<BinaryFile>>& binaryFiles, const ClassIdMap& classIdMap, bool debug)
1212 {
1213 Section* executableDataSection = executable.dataSection;
1214 long prevPos = executableDataSection->pos;
1215 executableDataSection->pos = executableDataSection->data.Count();
1216 executableDataSection->Align(8u);
1217 Symbol* debugInfoSymbol = new Symbol();
1218 debugInfoSymbol->name = "@debug_info";
1219 debugInfoSymbol->segment = Segment.data;
1220 debugInfoSymbol->linkage = Linkage.external;
1221 debugInfoSymbol->value = Value(cast<Value.Flag>(Value.Flag.pure | Value.Flag.address), executableDataSection->Address(), debugInfoSymbol);
1222 debugInfoSymbol->start = cmsx.machine.dataSegmentBaseAddress + executableDataSection->Address();
1223 executableDataSection->pos = executableDataSection->data.Count();
1224 List<FunctionTableEntry> functionTable;
1225 HashSet<ulong> functionAddressSet;
1226 HashMap<string, ulong> sourceFileNameAddressMap;
1227 for (const UniquePtr<BinaryFile>& binaryFile : binaryFiles)
1228 {
1229 if (binaryFile.Get() is ObjectFile*)
1230 {
1231 ObjectFile* objectFile = cast<ObjectFile*>(binaryFile.Get());
1232 ProcessDebugSection(executable, objectFile, sourceFileNameAddressMap, functionTable, functionAddressSet, classIdMap, debug);
1233 }
1234 else if (binaryFile.Get() is LibraryFile*)
1235 {
1236 LibraryFile* libraryFile = cast<LibraryFile*>(binaryFile.Get());
1237 for (const UniquePtr<ObjectFile>& objectFile : libraryFile->objectFiles)
1238 {
1239 ProcessDebugSection(executable, objectFile.Get(), sourceFileNameAddressMap, functionTable, functionAddressSet, classIdMap, debug);
1240 }
1241 }
1242 }
1243 Sort(functionTable);
1244 executableDataSection->Align(8u);
1245 ulong functionTableAddress = cmsx.machine.dataSegmentBaseAddress + executableDataSection->Address();
1246 for (const FunctionTableEntry& entry : functionTable)
1247 {
1248 executableDataSection->EmitULong(entry.start);
1249 executableDataSection->EmitULong(entry.length);
1250 executableDataSection->EmitULong(entry.mangledNameAddress);
1251 executableDataSection->EmitULong(entry.fullNameAddress);
1252 executableDataSection->EmitULong(entry.sourceFileNameAddress);
1253 executableDataSection->EmitULong(entry.lineNumberTableStartAddress);
1254 executableDataSection->EmitULong(entry.lineNumberTableEndAddress);
1255 executableDataSection->EmitULong(entry.exceptionTableAddress);
1256 }
1257 Symbol* functionTableSymbol = new Symbol();
1258 functionTableSymbol->name = "@function_table";
1259 functionTableSymbol->segment = Segment.data;
1260 functionTableSymbol->linkage = Linkage.external;
1261 functionTableSymbol->value = Value(cast<Value.Flag>(Value.Flag.pure | Value.Flag.address), functionTableAddress, functionTableSymbol);
1262 functionTableSymbol->start = functionTableAddress;
1263 functionTableSymbol->length = cmsx.machine.dataSegmentBaseAddress + executableDataSection->Address() - functionTableSymbol->start;
1264 functionTableSymbol->section = executableDataSection;
1265 executable.GetSymbolTable().AddSymbol(functionTableSymbol);
1266 debugInfoSymbol->length = cmsx.machine.dataSegmentBaseAddress + executableDataSection->Address() - debugInfoSymbol->start;
1267 debugInfoSymbol->section = executableDataSection;
1268 executable.GetSymbolTable().AddSymbol(debugInfoSymbol);
1269 executableDataSection->pos = prevPos;
1270 }
1271
1272 public void Link(ExecutableFile& executable, List<UniquePtr<BinaryFile>>& binaryFiles, const ClassIdMap& classIdMap, bool removeUnusedCode, bool debug)
1273 {
1274 LinkTable linkTable(classIdMap);
1275 linkTable.AddUsedSymbolName("Main");
1276 if (removeUnusedCode)
1277 {
1278 for (const UniquePtr<BinaryFile>& binaryFile : binaryFiles)
1279 {
1280 if (binaryFile.Get() is ObjectFile*)
1281 {
1282 ObjectFile* objectFile = cast<ObjectFile*>(binaryFile.Get());
1283 MarkUsedSymbols(linkTable, objectFile, debug);
1284 }
1285 else if (binaryFile.Get() is LibraryFile*)
1286 {
1287 LibraryFile* libraryFile = cast<LibraryFile*>(binaryFile.Get());
1288 for (const UniquePtr<ObjectFile>& objectFile : libraryFile->objectFiles)
1289 {
1290 MarkUsedSymbols(linkTable, objectFile.Get(), debug);
1291 }
1292 }
1293 else
1294 {
1295 throw Exception("cannot link '" + binaryFile->FileName() + "': not an object or library file");
1296 }
1297 }
1298 }
1299 CodeSection* prevCodeSection = null;
1300 DataSection* prevDataSection = null;
1301 for (const UniquePtr<BinaryFile>& binaryFile : binaryFiles)
1302 {
1303 if (binaryFile.Get() is ObjectFile*)
1304 {
1305 ObjectFile* objectFile = cast<ObjectFile*>(binaryFile.Get());
1306 LinkObjectFile(linkTable, executable, objectFile, prevCodeSection, prevDataSection, removeUnusedCode, debug);
1307 }
1308 else if (binaryFile.Get() is LibraryFile*)
1309 {
1310 LibraryFile* libraryFile = cast<LibraryFile*>(binaryFile.Get());
1311 for (const UniquePtr<ObjectFile>& objectFile : libraryFile->objectFiles)
1312 {
1313 LinkObjectFile(linkTable, executable, objectFile.Get(), prevCodeSection, prevDataSection, removeUnusedCode, debug);
1314 }
1315 }
1316 else
1317 {
1318 throw Exception("cannot link '" + binaryFile->FileName() + "': not an object or library file");
1319 }
1320 }
1321 linkTable.ReportUnresolvedSymbols();
1322 linkTable.CopyRanges(debug);
1323 MakeFuctionTable(executable, binaryFiles, classIdMap, debug);
1324 executable.Finalize();
1325 executable.Write();
1326 }
1327 }