1 using System;
   2 using System.Collections;
   3 
   4 namespace cmsx.object
   5 {
   6     public enum LinkCode : byte
   7     {
   8         forwardLongJump = 1uforwardShortJump = 2uabsoluteAddrValue = 3ufarJump = 4ufarOcta = 5uclsid = 6uend = 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 valuebool 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 valuebool 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(addressoffset);
  75             offset = (cast<ushort>(b5) << 8u) | cast<ushort>(b4);
  76             objectFile->codeSection->EmitShortOffset(address + 4uoffset);
  77             offset = (cast<ushort>(b3) << 8u) | cast<ushort>(b2);
  78             objectFile->codeSection->EmitShortOffset(address + 8uoffset);
  79             offset = (cast<ushort>(b1) << 8u) | cast<ushort>(b0);
  80             objectFile->codeSection->EmitShortOffset(address + 12uoffset);
  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 valuebool debug)
  90         {
  91             if (debug)
  92             {
  93                 Console.Out() << objectFile->FileName() << ": LINKFAROCTA(" << ToHexString(address) << " : " << ToHexString(value) << ")" << endl();
  94             }
  95             objectFile->dataSection->EmitULong(addressvalue);
  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 valuebool debug)
 105         {
 106             if (debug)
 107             {
 108                 Console.Out() << objectFile->FileName() << ": LINKCLSID(" << ToHexString(address) << " : " << ToHexString(classId) << ")" << endl();
 109             }
 110             objectFile->dataSection->EmitULong(addressclassId);
 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& symbolNameLinkCommand* command)
 138         {
 139             List<LinkCommand*>& commands = linkCommandMap[symbolName];
 140             commands.Add(command);
 141         }
 142         public void ExecuteLinkCommands(const string& symbolNameulong valuebool debug)
 143         {
 144             Map<stringList<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(valuedebug);
 155                     delete command;
 156                 }
 157                 linkCommandMap.Remove(symbolName);
 158             }
 159         }
 160         public void AddCopyRange(const CopyRange& copyRangebool 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<stringList<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<stringList<LinkCommand*>>& p : linkCommandMap)
 254             {
 255                 for (LinkCommand* command : p.second)
 256                 {
 257                     delete command;
 258                 }
 259             }
 260         }
 261         public void AddUnprocessedSymbol(Symbol* symbolSection* sectionSymbolTable* symbolTable)
 262         {
 263             List<Pair<Symbol*Pair<Section*SymbolTable*>>>& unprocessedSymbolList = unprocessedSymbolLists[symbol->name];
 264             unprocessedSymbolList.Add(MakePair(symbolMakePair(sectionsymbolTable)));
 265         }
 266         public List<Pair<Symbol*Pair<Section*SymbolTable*>>>* GetUnprocessedSymbolList(const string& symbolName)
 267         {
 268             HashMap<stringList<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<stringList<LinkCommand*>> linkCommandMap;
 279         private List<CopyRange> copyRanges;
 280         private const ClassIdMap& classIdMap;
 281         private HashSet<string> usedSymbolNames;
 282         private HashMap<stringList<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(fromAddresscast<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(fromAddresscast<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& linkTableExecutableFile& executableObjectFile* objectFilebool removeUnusedCodebool 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(executableSymboltrue);
 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->namesymbol->startdebug);
 451                                 linkTable.AddCopyRange(CopyRange(symbol->sectionsymbol->section->copyTargetSectionsymbol->value.valuesymbol->lengthsymbol->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->namesymbol->startdebug);
 511                                 linkTable.AddCopyRange(CopyRange(symbol->sectionsymbol->section->copyTargetSectionsymbol->value.valuesymbol->lengthsymbol->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(linkTableexecutableobjectFilelinkSymboldebug);
 553         }
 554     }
 555 
 556     public void ProcessLinkSection(LinkTable& linkTableExecutableFile& executableObjectFile* objectFileSymbol* forSymbolbool 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(objectFileaddress));
 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(objectFileaddress));
 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(typeId1typeId2);
 622                     linkCommand.Reset(new LinkClsIdCommand(objectFileaddresslinkTable.GetClassId(typeId)));
 623                     linkCommand->Execute(0udebug);
 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->startdebug);
 639                 }
 640                 else if (symbol->value.flags == Value.Flag.undefined)
 641                 {
 642                     linkTable.AddLinkCommand(symbol->namelinkCommand.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& linkTableExecutableFile& executableObjectFile* objectFileSection*& prevCodeSectionSection*& prevDataSectionbool removeUnusedCodebool 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(linkTableexecutableobjectFileremoveUnusedCodedebug);
 699         if (debug)
 700         {
 701             Console.Out() << "end linking " << objectFile->FileName() << endl();
 702         }
 703     }
 704 
 705     public void ProcessUsedSymbol(Symbol* symbolSymbolTable& symbolTableLinkTable& linkTableSection* linkSectionbool 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(*unprocessedSymbolssymbols);
 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*stablinkTablesectiondebug);
 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& linkTableObjectFile* objectFilebool 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()linkTableobjectFile->linkSectiondebug);
 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>& dispatchTableconst DispatchTableEntry& entrySection* 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.offsetentry.offset - prevEntry.offsetprevEntry.exceptionBlockTableAddressprevEntry.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& executableconst 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.offsettryBlock.lengthexceptionBlockTableAddress&tryBlock);
 899                     dispatchTable = InsertIntoDispatchTable(dispatchTableentryexecutableDataSection);
 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.offsetcleanupDispatchBlock.lengthexceptionBlockTableAddress&cleanupDispatchBlock);
 912                     dispatchTable = InsertIntoDispatchTable(dispatchTableentryexecutableDataSection);
 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& executableObjectFile* objectFileHashMap<stringulong>& stringAddressMapList<FunctionTableEntry>& functionTable
 936         HashSet<ulong>& functionAddressSetconst ClassIdMap& classIdMapbool 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<uintulong> sourceFileIdAddressMap;
 945         HashMap<stringLineNumberTableLimits> lineNumberTableMap;
 946         HashMap<stringulong> 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<stringulong>.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<uintulong>.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<stringulong>.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<stringulong>.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<stringulong>.ConstIterator it3 = exceptionTableAddressMap.CFind(functionSymbol->name);
1028                                 if (it3 != exceptionTableAddressMap.CEnd())
1029                                 {
1030                                     exceptionTableAddress = it3->second;
1031                                     executable.dataSection->EmitUInt(exceptionTableAddressframeSize);
1032                                 }
1033                                 LineNumberTableLimits& lineNumberTable = lineNumberTableMap[functionSymbol->name];
1034                                 FunctionTableEntry entry(finalFunctionSymbol->startfinalFunctionSymbol->lengthmangledNameAddressfullNameAddresssourceFileNameAddress
1035                                     lineNumberTable.startAddresslineNumberTable.endAddressexceptionTableAddress);
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(executablefunctionExceptionData);
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(tryBlockIdparentTryBlockIdoffset);
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(catchedTypeId1catchedTypeId2);
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(catchedClassIdhandlerAddress);
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(cleanupBlockIdtryBlockoffset);
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(cleanupAddess0u);
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& executableList<UniquePtr<BinaryFile>>& binaryFilesconst ClassIdMap& classIdMapbool 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<stringulong> 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(executableobjectFilesourceFileNameAddressMapfunctionTablefunctionAddressSetclassIdMapdebug);
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(executableobjectFile.Get()sourceFileNameAddressMapfunctionTablefunctionAddressSetclassIdMapdebug);
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)functionTableAddressfunctionTableSymbol);
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& executableList<UniquePtr<BinaryFile>>& binaryFilesconst ClassIdMap& classIdMapbool removeUnusedCodebool 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(linkTableobjectFiledebug);
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(linkTableobjectFile.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(linkTableexecutableobjectFileprevCodeSectionprevDataSectionremoveUnusedCodedebug);
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(linkTableexecutableobjectFile.Get()prevCodeSectionprevDataSectionremoveUnusedCodedebug);
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(executablebinaryFilesclassIdMapdebug);
1324         executable.Finalize();
1325         executable.Write();
1326     }
1327 }