1//===- ELFWriter.cpp ------------------------------------------------------===// 2// 3// The MCLinker Project 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9#include <llvm/Support/ELF.h> 10#include <llvm/Support/ErrorHandling.h> 11#include <llvm/MC/MCAssembler.h> 12#include <mcld/ADT/SizeTraits.h> 13#include <mcld/Support/MemoryRegion.h> 14#include <mcld/MC/MCLDInfo.h> 15#include <mcld/MC/MCLinker.h> 16#include <mcld/MC/MCRegionFragment.h> 17#include <mcld/LD/ELFWriter.h> 18#include <mcld/LD/LDSymbol.h> 19#include <mcld/LD/LDSection.h> 20#include <mcld/LD/Layout.h> 21#include <mcld/Target/GNULDBackend.h> 22#include <cstdlib> 23#include <cstring> 24 25using namespace llvm::ELF; 26using namespace mcld; 27 28/// writeELF32Header - write ELF header 29void ELFWriter::writeELF32Header(const MCLDInfo& pLDInfo, 30 const Layout& pLayout, 31 const GNULDBackend& pBackend, 32 Output& pOutput) const 33{ 34 assert(pOutput.hasMemArea()); 35 36 // ELF header must start from 0x0 37 MemoryRegion *region = pOutput.memArea()->request(0, 38 sizeof(Elf32_Ehdr)); 39 Elf32_Ehdr* header = (Elf32_Ehdr*)region->start(); 40 41 memcpy(header->e_ident, ElfMagic, EI_MAG3+1); 42 43 header->e_ident[EI_CLASS] = ELFCLASS32; 44 header->e_ident[EI_DATA] = pBackend.isLittleEndian()? 45 ELFDATA2LSB : ELFDATA2MSB; 46 header->e_ident[EI_VERSION] = pBackend.ELFVersion(); 47 header->e_ident[EI_OSABI] = pBackend.OSABI(); 48 header->e_ident[EI_ABIVERSION] = pBackend.ABIVersion(); 49 50 // FIXME: add processor-specific and core file types. 51 switch(pOutput.type()) { 52 case Output::Object: 53 header->e_type = ET_REL; 54 break; 55 case Output::DynObj: 56 header->e_type = ET_DYN; 57 break; 58 case Output::Exec: 59 header->e_type = ET_EXEC; 60 break; 61 default: 62 llvm::errs() << "unspported output file type: " << pOutput.type() << ".\n"; 63 header->e_type = ET_NONE; 64 } 65 header->e_machine = pBackend.machine(); 66 header->e_version = header->e_ident[EI_VERSION]; 67 header->e_entry = getEntryPoint(pLDInfo, pLayout, pBackend, pOutput); 68 header->e_phoff = sizeof(Elf32_Ehdr); 69 header->e_shoff = getELF32LastStartOffset(pOutput); 70 header->e_flags = pBackend.flags(); 71 header->e_ehsize = sizeof(Elf32_Ehdr); 72 header->e_phentsize = sizeof(Elf32_Phdr); 73 header->e_phnum = pBackend.numOfSegments(); 74 header->e_shentsize = sizeof(Elf32_Shdr); 75 header->e_shnum = pOutput.context()->numOfSections(); 76 header->e_shstrndx = pOutput.context()->getSectionIdx(".shstrtab"); 77} 78 79/// writeELF64Header - write ELF header 80void ELFWriter::writeELF64Header(const MCLDInfo& pLDInfo, 81 const Layout& pLayout, 82 const GNULDBackend& pBackend, 83 Output& pOutput) const 84{ 85 assert(pOutput.hasMemArea()); 86 87 // ELF header must start from 0x0 88 MemoryRegion *region = pOutput.memArea()->request(0, 89 sizeof(Elf64_Ehdr)); 90 Elf64_Ehdr* header = (Elf64_Ehdr*)region->start(); 91 92 memcpy(header->e_ident, ElfMagic, EI_MAG3+1); 93 94 header->e_ident[EI_CLASS] = ELFCLASS64; 95 header->e_ident[EI_DATA] = pBackend.isLittleEndian()? 96 ELFDATA2LSB : ELFDATA2MSB; 97 header->e_ident[EI_VERSION] = pBackend.ELFVersion(); 98 header->e_ident[EI_OSABI] = pBackend.OSABI(); 99 header->e_ident[EI_ABIVERSION] = pBackend.ABIVersion(); 100 101 // FIXME: add processor-specific and core file types. 102 switch(pOutput.type()) { 103 case Output::Object: 104 header->e_type = ET_REL; 105 break; 106 case Output::DynObj: 107 header->e_type = ET_DYN; 108 break; 109 case Output::Exec: 110 header->e_type = ET_EXEC; 111 break; 112 default: 113 llvm::errs() << "unspported output file type: " << pOutput.type() << ".\n"; 114 header->e_type = ET_NONE; 115 } 116 header->e_machine = pBackend.machine(); 117 header->e_version = header->e_ident[EI_VERSION]; 118 header->e_entry = getEntryPoint(pLDInfo, pLayout, pBackend, pOutput); 119 header->e_phoff = sizeof(Elf64_Ehdr); 120 header->e_shoff = getELF64LastStartOffset(pOutput); 121 header->e_flags = pBackend.flags(); 122 header->e_ehsize = sizeof(Elf64_Ehdr); 123 header->e_phentsize = sizeof(Elf64_Phdr); 124 header->e_phnum = pBackend.numOfSegments(); 125 header->e_shentsize = sizeof(Elf64_Shdr); 126 header->e_shnum = pOutput.context()->numOfSections(); 127 header->e_shstrndx = pOutput.context()->getSectionIdx(".shstrtab"); 128} 129 130/// getEntryPoint 131uint64_t ELFWriter::getEntryPoint(const MCLDInfo& pLDInfo, 132 const Layout& pLayout, 133 const GNULDBackend& pBackend, 134 const Output& pOutput) const 135{ 136 137 llvm::StringRef entry_name; 138 if (pLDInfo.options().hasEntry()) 139 entry_name = pLDInfo.options().entry(); 140 else 141 entry_name = pBackend.entry(); 142 143 uint64_t result = 0x0; 144 145 bool issue_warning = (pLDInfo.options().hasEntry() 146 && (pOutput.type() != Output::Object) 147 && (pOutput.type() != Output::DynObj)); 148 149 const LDSymbol* entry_symbol = pLDInfo.getStrSymPool().findSymbol(entry_name); 150 151 // found the symbol 152 if (NULL != entry_symbol) { 153 if (entry_symbol->desc() != ResolveInfo::Define && issue_warning) { 154 llvm::errs() << "WARNING: entry symbol '" 155 << entry_symbol->name() 156 << "' exists but is not defined.\n"; 157 } 158 result = entry_symbol->value(); 159 } 160 // not in the symbol pool 161 else { 162 // We should parse entry as a number. 163 // @ref GNU ld manual, Options -e. e.g., -e 0x1000. 164 char* endptr; 165 result = strtoull(entry_name.data(), &endptr, 0); 166 if (*endptr != '\0') { 167 if (issue_warning) { 168 llvm::errs() << "cannot find entry symbol '" 169 << entry_name.data() 170 << "'.\n"; 171 } 172 result = 0x0; 173 } 174 } 175 return result; 176} 177 178/// emitELF32SectionHeader - emit Elf32_Shdr 179void 180ELFWriter::emitELF32SectionHeader(Output& pOutput, MCLinker& pLinker) const 181{ 182 // emit section header 183 unsigned int sectNum = pOutput.context()->numOfSections(); 184 unsigned int header_size = sizeof(Elf32_Shdr) * sectNum; 185 MemoryRegion* region = pOutput.memArea()->request( 186 getELF32LastStartOffset(pOutput), 187 header_size); 188 Elf32_Shdr* shdr = (Elf32_Shdr*)region->start(); 189 190 // Iterate the SectionTable in LDContext 191 unsigned int sectIdx = 0; 192 unsigned int shstridx = 0; // NULL section has empty name 193 for (; sectIdx < sectNum; ++sectIdx) { 194 const LDSection *ld_sect = pOutput.context()->getSection(sectIdx); 195 shdr[sectIdx].sh_name = shstridx; 196 shdr[sectIdx].sh_type = ld_sect->type(); 197 shdr[sectIdx].sh_flags = ld_sect->flag(); 198 shdr[sectIdx].sh_addr = ld_sect->addr(); 199 shdr[sectIdx].sh_offset = ld_sect->offset(); 200 shdr[sectIdx].sh_size = ld_sect->size(); 201 shdr[sectIdx].sh_addralign = ld_sect->align(); 202 shdr[sectIdx].sh_entsize = getELF32SectEntrySize(*ld_sect); 203 shdr[sectIdx].sh_link = getSectLink(*ld_sect, pOutput); 204 shdr[sectIdx].sh_info = getSectInfo(*ld_sect, pOutput); 205 206 // adjust strshidx 207 shstridx += ld_sect->name().size() + 1; 208 } 209} 210 211/// emitELF64SectionHeader - emit Elf64_Shdr 212void 213ELFWriter::emitELF64SectionHeader(Output& pOutput, MCLinker& pLinker) const 214{ 215 // emit section header 216 unsigned int sectNum = pOutput.context()->numOfSections(); 217 unsigned int header_size = sizeof(Elf64_Shdr) * sectNum; 218 MemoryRegion* region = pOutput.memArea()->request( 219 getELF64LastStartOffset(pOutput), 220 header_size); 221 Elf64_Shdr* shdr = (Elf64_Shdr*)region->start(); 222 223 // Iterate the SectionTable in LDContext 224 unsigned int sectIdx = 0; 225 unsigned int shstridx = 0; // NULL section has empty name 226 for (; sectIdx < sectNum; ++sectIdx) { 227 const LDSection *ld_sect = pOutput.context()->getSection(sectIdx); 228 shdr[sectIdx].sh_name = shstridx; 229 shdr[sectIdx].sh_type = ld_sect->type(); 230 shdr[sectIdx].sh_flags = ld_sect->flag(); 231 shdr[sectIdx].sh_addr = ld_sect->addr(); 232 shdr[sectIdx].sh_offset = ld_sect->offset(); 233 shdr[sectIdx].sh_size = ld_sect->size(); 234 shdr[sectIdx].sh_addralign = (ld_sect->hasSectionData())? 235 ld_sect->getSectionData()->getAlignment(): 236 0x0; 237 238 shdr[sectIdx].sh_entsize = getELF64SectEntrySize(*ld_sect); 239 shdr[sectIdx].sh_link = getSectLink(*ld_sect, pOutput); 240 shdr[sectIdx].sh_info = getSectInfo(*ld_sect, pOutput); 241 242 // adjust strshidx 243 shstridx += ld_sect->name().size() + 1; 244 } 245} 246 247/// emitELF32ShStrTab - emit section string table 248void ELFWriter::emitELF32ShStrTab(Output& pOutput, MCLinker& pLinker) const 249{ 250 uint64_t shstroffset = getELF32LastStartOffset(pOutput); 251 252 // get shstrtab 253 LDSection& shstrtab = pLinker.getOrCreateOutputSectHdr(".shstrtab", 254 LDFileFormat::NamePool, 255 SHT_STRTAB, 256 0x0); 257 if (0 != shstrtab.size()) 258 llvm::report_fatal_error(".shstrtab has been set.\n"); 259 260 // compute size 261 unsigned int shstrsize = 0; 262 LDContext::const_sect_iterator section, sectEnd = pOutput.context()->sectEnd(); 263 for (section = pOutput.context()->sectBegin(); section != sectEnd; ++section) { 264 shstrsize += (*section)->name().size() + 1; 265 } 266 267 shstrtab.setSize(shstrsize); 268 shstrtab.setOffset(shstroffset); 269 270 // write out data 271 MemoryRegion* region = pOutput.memArea()->request(shstrtab.offset(), 272 shstrtab.size()); 273 unsigned char* data = region->start(); 274 shstrsize = 0; 275 for (section = pOutput.context()->sectBegin(); section != sectEnd; ++section) { 276 strcpy((char*)(data + shstrsize), (*section)->name().c_str()); 277 shstrsize += (*section)->name().size() + 1; 278 } 279 280 shstrtab.setKind(LDFileFormat::NamePool); 281 shstrtab.setType(llvm::ELF::SHT_STRTAB); 282 shstrtab.setFlag(0x0); 283 shstrtab.setAddr(0x0); 284} 285 286 287/// emitELF64ShStrTab - emit section string table 288void ELFWriter::emitELF64ShStrTab(Output& pOutput, MCLinker& pLinker) const 289{ 290 uint64_t shstroffset = getELF64LastStartOffset(pOutput); 291 292 // get shstrtab 293 LDSection& shstrtab = pLinker.getOrCreateOutputSectHdr(".shstrtab", 294 LDFileFormat::NamePool, 295 SHT_STRTAB, 296 0x0); 297 if (0 != shstrtab.size()) 298 llvm::report_fatal_error(".shstrtab has been set.\n"); 299 300 // compute offset 301 302 // compute size 303 unsigned int shstrsize = 0; 304 LDContext::const_sect_iterator section, sectEnd = pOutput.context()->sectEnd(); 305 for (section = pOutput.context()->sectBegin(); section != sectEnd; ++section) { 306 shstrsize += (*section)->name().size() + 1; 307 } 308 309 shstrtab.setSize(shstrsize); 310 shstrtab.setOffset(shstroffset); 311 312 // write out data 313 MemoryRegion* region = pOutput.memArea()->request(shstrtab.offset(), 314 shstrtab.size()); 315 unsigned char* data = region->start(); 316 shstrsize = 0; 317 for (section = pOutput.context()->sectBegin(); section != sectEnd; ++section) { 318 strcpy((char*)(data + shstrsize), (*section)->name().c_str()); 319 shstrsize += (*section)->name().size() + 1; 320 } 321 322 shstrtab.setKind(LDFileFormat::NamePool); 323 shstrtab.setType(llvm::ELF::SHT_STRTAB); 324 shstrtab.setFlag(0x0); 325 shstrtab.setAddr(0x0); 326} 327 328/// emitSectionData 329void 330ELFWriter::emitSectionData(const Layout& pLayout, 331 const LDSection& pSection, 332 MemoryRegion& pRegion) const 333{ 334 const llvm::MCSectionData* data = pSection.getSectionData(); 335 llvm::MCSectionData::const_iterator fragIter, fragEnd = data->end(); 336 size_t cur_offset = 0; 337 for (fragIter = data->begin(); fragIter != fragEnd; ++fragIter) { 338 size_t size = computeFragmentSize(pLayout, *fragIter); 339 switch(fragIter->getKind()) { 340 case llvm::MCFragment::FT_Region: { 341 const MCRegionFragment& region_frag = llvm::cast<MCRegionFragment>(*fragIter); 342 const uint8_t* from = region_frag.getRegion().start(); 343 memcpy(pRegion.getBuffer(cur_offset), from, size); 344 break; 345 } 346 case llvm::MCFragment::FT_Align: { 347 // TODO: emit values with different sizes (> 1 byte), and emit nops 348 llvm::MCAlignFragment& align_frag = llvm::cast<llvm::MCAlignFragment>(*fragIter); 349 uint64_t count = size / align_frag.getValueSize(); 350 switch (align_frag.getValueSize()) { 351 case 1u: 352 std::memset(pRegion.getBuffer(cur_offset), 353 align_frag.getValue(), 354 count); 355 break; 356 default: 357 llvm::report_fatal_error("unsupported value size for align fragment emission yet.\n"); 358 break; 359 } 360 break; 361 } 362 case llvm::MCFragment::FT_Fill: { 363 llvm::MCFillFragment& fill_frag = llvm::cast<llvm::MCFillFragment>(*fragIter); 364 if (0 == size || 365 0 == fill_frag.getValueSize() || 366 0 == fill_frag.getSize()) { 367 // ignore virtual fillment 368 break; 369 } 370 371 uint64_t num_tiles = fill_frag.getSize() / fill_frag.getValueSize(); 372 for (uint64_t i = 0; i != num_tiles; ++i) { 373 std::memset(pRegion.getBuffer(cur_offset), 374 fill_frag.getValue(), 375 fill_frag.getValueSize()); 376 } 377 break; 378 } 379 case llvm::MCFragment::FT_Data: 380 case llvm::MCFragment::FT_Inst: 381 case llvm::MCFragment::FT_Org: 382 case llvm::MCFragment::FT_Dwarf: 383 case llvm::MCFragment::FT_DwarfFrame: 384 case llvm::MCFragment::FT_LEB: { 385 llvm::report_fatal_error("unsupported fragment yet.\n"); 386 break; 387 } 388 case llvm::MCFragment::FT_Reloc: 389 llvm::report_fatal_error("relocation fragment should not be in a regular section.\n"); 390 break; 391 case llvm::MCFragment::FT_Target: 392 llvm::report_fatal_error("Target fragment should not be in a regular section.\n"); 393 break; 394 default: 395 llvm::report_fatal_error("invalid fragment should not be in a regular section.\n"); 396 break; 397 } 398 cur_offset += size; 399 } 400} 401 402/// emitRelocation 403void ELFWriter::emitRelocation(const Layout& pLayout, 404 const Output& pOutput, 405 const LDSection& pSection, 406 MemoryRegion& pRegion) const 407{ 408 const llvm::MCSectionData* SectionData = pSection.getSectionData(); 409 assert(SectionData && "SectionData is NULL in emitRelocation!"); 410 411 if (pSection.type() == SHT_REL) 412 emitRel(pLayout, pOutput, *SectionData, pRegion); 413 else if (pSection.type() == SHT_RELA) 414 emitRela(pLayout, pOutput, *SectionData, pRegion); 415 else 416 llvm::report_fatal_error("unsupported relocation section type!"); 417} 418 419 420/// emitRel 421void ELFWriter::emitRel(const Layout& pLayout, 422 const Output& pOutput, 423 const llvm::MCSectionData& pSectionData, 424 MemoryRegion& pRegion) const 425{ 426 Elf32_Rel* rel = reinterpret_cast<Elf32_Rel*>(pRegion.start()); 427 428 Relocation* relocation = 0; 429 MCFragmentRef* FragmentRef = 0; 430 431 for (llvm::MCSectionData::const_iterator it = pSectionData.begin(), 432 ie = pSectionData.end(); it != ie; ++it, ++rel) { 433 434 relocation = &(llvm::cast<Relocation>(*it)); 435 FragmentRef = &(relocation->targetRef()); 436 437 if(pOutput.type() == Output::DynObj || pOutput.type() == Output::Exec) { 438 rel->r_offset = static_cast<Elf32_Addr>( 439 llvm::cast<LDSection>( 440 FragmentRef->frag()->getParent()->getSection()).addr() + 441 pLayout.getOutputOffset(*FragmentRef)); 442 } 443 else { 444 rel->r_offset = static_cast<Elf32_Addr>( 445 llvm::cast<LDSection>( 446 FragmentRef->frag()->getParent()->getSection()).offset() + 447 pLayout.getOutputOffset(*FragmentRef)); 448 } 449 450 Elf32_Word Index; 451 if( relocation->symInfo() == NULL ) 452 Index = 0; 453 else 454 Index = static_cast<Elf32_Word>( 455 f_Backend.getSymbolIdx(relocation->symInfo()->outSymbol())); 456 457 rel->setSymbolAndType(Index, relocation->type()); 458 } 459} 460 461/// emitRela 462void ELFWriter::emitRela(const Layout& pLayout, 463 const Output& pOutput, 464 const llvm::MCSectionData& pSectionData, 465 MemoryRegion& pRegion) const 466{ 467 Elf32_Rela* rel = reinterpret_cast<Elf32_Rela*>(pRegion.start()); 468 469 Relocation* relocation = 0; 470 MCFragmentRef* FragmentRef = 0; 471 472 for (llvm::MCSectionData::const_iterator it = pSectionData.begin(), 473 ie = pSectionData.end(); it != ie; ++it, ++rel) { 474 475 relocation = &(llvm::cast<Relocation>(*it)); 476 FragmentRef = &(relocation->targetRef()); 477 478 if(pOutput.type() == Output::DynObj || pOutput.type() == Output::Exec) { 479 rel->r_offset = static_cast<Elf32_Addr>( 480 llvm::cast<LDSection>( 481 FragmentRef->frag()->getParent()->getSection()).addr() + 482 pLayout.getOutputOffset(*FragmentRef)); 483 } 484 else { 485 rel->r_offset = static_cast<Elf32_Addr>( 486 llvm::cast<LDSection>( 487 FragmentRef->frag()->getParent()->getSection()).offset() + 488 pLayout.getOutputOffset(*FragmentRef)); 489 } 490 491 Elf32_Word Index; 492 if( relocation->symInfo() == NULL ) 493 Index = 0; 494 else 495 Index = static_cast<Elf32_Word>( 496 f_Backend.getSymbolIdx(relocation->symInfo()->outSymbol())); 497 498 rel->setSymbolAndType(Index, relocation->type()); 499 rel->r_addend = relocation->addend(); 500 } 501} 502 503/// getELF32SectEntrySize - compute Elf32_Shdr::sh_entsize 504uint64_t ELFWriter::getELF32SectEntrySize(const LDSection& pSection) const 505{ 506 if (llvm::ELF::SHT_DYNSYM == pSection.type() || 507 llvm::ELF::SHT_SYMTAB == pSection.type()) 508 return sizeof(llvm::ELF::Elf32_Sym); 509 if (llvm::ELF::SHT_REL == pSection.type()) 510 return sizeof(llvm::ELF::Elf32_Rel); 511 if (llvm::ELF::SHT_RELA == pSection.type()) 512 return sizeof(llvm::ELF::Elf32_Rela); 513 if (llvm::ELF::SHT_HASH == pSection.type()) 514 return sizeof(llvm::ELF::Elf32_Word); 515 if (llvm::ELF::SHT_DYNAMIC == pSection.type()) 516 return sizeof(llvm::ELF::Elf32_Dyn); 517 return 0x0; 518} 519 520/// getELF64SectEntrySize - compute Elf64_Shdr::sh_entsize 521uint64_t ELFWriter::getELF64SectEntrySize(const LDSection& pSection) const 522{ 523 if (llvm::ELF::SHT_DYNSYM == pSection.type() || 524 llvm::ELF::SHT_SYMTAB == pSection.type()) 525 return sizeof(llvm::ELF::Elf64_Sym); 526 if (llvm::ELF::SHT_REL == pSection.type()) 527 return sizeof(llvm::ELF::Elf64_Rel); 528 if (llvm::ELF::SHT_RELA == pSection.type()) 529 return sizeof(llvm::ELF::Elf64_Rela); 530 if (llvm::ELF::SHT_HASH == pSection.type()) 531 return sizeof(llvm::ELF::Elf64_Word); 532 if (llvm::ELF::SHT_DYNAMIC == pSection.type()) 533 return sizeof(llvm::ELF::Elf64_Dyn); 534 return 0x0; 535} 536 537/// getSectLink - compute ElfXX_Shdr::sh_link 538uint64_t ELFWriter::getSectLink(const LDSection& pSection, const Output& pOutput) const 539{ 540 const LDContext* context = pOutput.context(); 541 if (llvm::ELF::SHT_SYMTAB == pSection.type()) 542 return context->getSectionIdx(".strtab"); 543 if (llvm::ELF::SHT_DYNSYM == pSection.type()) 544 return context->getSectionIdx(".dynstr"); 545 if (llvm::ELF::SHT_DYNAMIC == pSection.type()) 546 return context->getSectionIdx(".dynstr"); 547 if (llvm::ELF::SHT_HASH == pSection.type()) 548 return context->getSectionIdx(".dynsym"); 549 if (llvm::ELF::SHT_REL == pSection.type() || 550 llvm::ELF::SHT_RELA == pSection.type()) { 551 if (pOutput.type() == Output::Object) 552 return context->getSectionIdx(".symtab"); 553 else 554 return context->getSectionIdx(".dynsym"); 555 } 556 return llvm::ELF::SHN_UNDEF; 557} 558 559/// getSectInfo - compute ElfXX_Shdr::sh_info 560uint64_t ELFWriter::getSectInfo(const LDSection& pSection, const Output& pOutput) const 561{ 562 const LDSection* info_link = pSection.getLink(); 563 if (NULL == info_link) 564 return 0x0; 565 return info_link->index(); 566} 567 568/// getELF32LastStartOffset 569uint64_t ELFWriter::getELF32LastStartOffset(const Output& pOutput) const 570{ 571 LDSection* lastSect = pOutput.context()->getSectionTable().back(); 572 assert(lastSect != NULL); 573 return Align<32>(lastSect->offset() + lastSect->size()); 574} 575 576/// getELF64LastStartOffset 577uint64_t ELFWriter::getELF64LastStartOffset(const Output& pOutput) const 578{ 579 LDSection* lastSect = pOutput.context()->getSectionTable().back(); 580 assert(lastSect != NULL); 581 return Align<64>(lastSect->offset() + lastSect->size()); 582} 583 584