diff --git a/lld/MachO/InputSection.h b/lld/MachO/InputSection.h --- a/lld/MachO/InputSection.h +++ b/lld/MachO/InputSection.h @@ -43,6 +43,7 @@ ArrayRef data; uint64_t addr = 0; uint32_t align = 1; + uint32_t n_sect = 0; uint32_t flags = 0; std::vector relocs; diff --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp --- a/lld/MachO/Writer.cpp +++ b/lld/MachO/Writer.cpp @@ -50,6 +50,7 @@ void assignAddresses(); void createDyldInfoContents(); + void createSymtabContents(); void openFile(); void writeHeader(); @@ -100,6 +101,7 @@ uint64_t fileOff = 0; uint64_t addr = 0; SmallVector contents; + raw_svector_ostream os{contents}; }; class LCDyldInfo : public LoadCommand { @@ -210,7 +212,16 @@ auto *c = reinterpret_cast(buf); c->cmd = LC_SYMTAB; c->cmdsize = getSize(); + c->symoff = symOff; + c->nsyms = nSyms; + c->stroff = strOff; + c->strsize = strSize; } + + uint64_t symOff = 0; + uint64_t nSyms = 0; + uint64_t strOff = 0; + uint64_t strSize = 0; }; class LCLoadDylib : public LoadCommand { @@ -312,6 +323,7 @@ sizeofCmds = size; addr += size; + uint64_t n_sect = 0; for (OutputSegment *seg : outputSegments) { addr = alignTo(addr, PageSize); @@ -321,6 +333,7 @@ addr = alignTo(addr, isec->align); isec->addr = addr; addr += isec->getSize(); + isec->n_sect = ++n_sect; } } } @@ -362,8 +375,52 @@ dyldInfoSeg->bindOff = sectionStart; dyldInfoSeg->bindSize = linkEditSeg->getOffset() - sectionStart; +} + +// TODO: Implement symbol export trie. +void Writer::createSymtabContents() { + uint64_t start = linkEditSeg->getOffset(); + + symtabSeg->symOff = start; + symtabSeg->nSyms = 0; + + SmallVector stringTable; + raw_svector_ostream stringTableOs{stringTable}; + // An n_strx value of 0 always indicates the empty string, so we must locate + // our non-empty string values at positive offsets in the string pool. + // Therefore we insert a dummy value at position zero. + stringTableOs << '\0'; + + auto &os = linkEditSeg->os; + for (Symbol *sym : symtab->getSymbols()) { + uint8_t n_type = N_UNDF; + uint8_t n_sect = NO_SECT; + uint32_t n_value = 0; + + if (auto defined = dyn_cast(sym)) { + n_type = (N_EXT | N_SECT); + n_sect = defined->isec->n_sect; - // TODO: Implement symbol export trie. + // For the N_SECT symbol type, n_value is the address of the symbol + n_value = defined->value + defined->isec->addr; + } + + ++symtabSeg->nSyms; + auto n_strx = stringTable.size(); + stringTableOs << sym->getName() << '\0'; + + // Emit one nlist_64 struct. + endian::write(os, n_strx, endianness::little); // n_strx + linkEditSeg->os << n_type; // n_type + linkEditSeg->os << n_sect; // n_sect + endian::write(os, 0, endianness::little); // n_dest + endian::write(os, n_value, endianness::little); // n_value + } + + // The string table is located right after the symbol table. + symtabSeg->strOff = start + symtabSeg->nSyms * sizeof(nlist_64); + symtabSeg->strSize = stringTable.size(); + os << stringTable; } void Writer::openFile() { @@ -414,6 +471,8 @@ // Fill __LINKEDIT contents createDyldInfoContents(); + createSymtabContents(); + fileSize = linkEditSeg->fileOff + linkEditSeg->contents.size(); openFile(); diff --git a/lld/test/MachO/symtab_basic.s b/lld/test/MachO/symtab_basic.s new file mode 100644 --- /dev/null +++ b/lld/test/MachO/symtab_basic.s @@ -0,0 +1,54 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t.o +# RUN: lld -flavor darwinnew -o %t %t.o +# RUN: llvm-readobj -symbols %t | FileCheck %s + +# CHECK: Symbols [ +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: _main +# CHECK-NEXT: Extern +# CHECK-NEXT: Type: Section (0xE) +# CHECK-NEXT: Section: __text (0x1) +# CHECK-NEXT: RefType: +# CHECK-NEXT: Flags [ (0x0) +# CHECK-NEXT: ] +# CHECK-NEXT: Value: +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: bar +# CHECK-NEXT: Extern +# CHECK-NEXT: Type: Section (0xE) +# CHECK-NEXT: Section: __text (0x1) +# CHECK-NEXT: RefType: +# CHECK-NEXT: Flags [ (0x0) +# CHECK-NEXT: ] +# CHECK-NEXT: Value: +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: foo +# CHECK-NEXT: Extern +# CHECK-NEXT: Type: Section (0xE) +# CHECK-NEXT: Section: __text (0x1) +# CHECK-NEXT: RefType: +# CHECK-NEXT: Flags [ (0x0) +# CHECK-NEXT: ] +# CHECK-NEXT: Value: +# CHECK-NEXT: } +# CHECK-NEXT: ] + +.text +.global bar +.global foo +.global _main + +_main: + mov $0, %rax + ret + +foo: + mov $1, %rax + ret + +bar: + mov $2, %rax + ret