diff --git a/lld/MachO/OutputSegment.h b/lld/MachO/OutputSegment.h --- a/lld/MachO/OutputSegment.h +++ b/lld/MachO/OutputSegment.h @@ -55,6 +55,7 @@ StringRef name; uint32_t maxProt = 0; uint32_t initProt = 0; + uint32_t flags = 0; uint8_t index; llvm::TinyPtrVector segmentStartSymbols; diff --git a/lld/MachO/OutputSegment.cpp b/lld/MachO/OutputSegment.cpp --- a/lld/MachO/OutputSegment.cpp +++ b/lld/MachO/OutputSegment.cpp @@ -44,6 +44,12 @@ return initProt(name); } +static uint32_t flags(StringRef name) { + // If we ever implement shared cache output support, SG_READ_ONLY should not + // be used for dylibs that can be placed in it. + return name == segment_names::dataConst ? SG_READ_ONLY : 0; +} + size_t OutputSegment::numNonHiddenSections() const { size_t count = 0; for (const OutputSection *osec : sections) @@ -185,6 +191,7 @@ segRef->name = name; segRef->maxProt = maxProt(name); segRef->initProt = initProt(name); + segRef->flags = flags(name); outputSegments.push_back(segRef); return segRef; diff --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp --- a/lld/MachO/Writer.cpp +++ b/lld/MachO/Writer.cpp @@ -246,6 +246,7 @@ c->vmsize = seg->vmSize; c->filesize = seg->fileSize; c->nsects = seg->numNonHiddenSections(); + c->flags = seg->flags; for (const OutputSection *osec : seg->getSections()) { if (osec->isHidden()) diff --git a/lld/test/MachO/builtin-rename.s b/lld/test/MachO/builtin-rename.s --- a/lld/test/MachO/builtin-rename.s +++ b/lld/test/MachO/builtin-rename.s @@ -53,6 +53,23 @@ # YDATA-DAG: __DATA_CONST,__objc_protolist __DATA__objc_protolist # YDATA-DAG: __DATA_CONST,__nl_symbol_ptr __IMPORT__pointers +## Check that the SG_READ_ONLY flag is set on __DATA_CONST. +# RUN: llvm-otool -v -l %t/ydata | \ +# RUN: FileCheck %s --check-prefix=FLAGS + +# FLAGS-LABEL: Load command 2 +# FLAGS-NEXT: cmd LC_SEGMENT_64 +# FLAGS-NEXT: cmdsize +# FLAGS-NEXT: segname __DATA_CONST +# FLAGS-NEXT: vmaddr +# FLAGS-NEXT: vmsize +# FLAGS-NEXT: fileoff +# FLAGS-NEXT: filesize +# FLAGS-NEXT: maxprot rw- +# FLAGS-NEXT: initprot rw- +# FLAGS-NEXT: nsects 13 +# FLAGS-NEXT: flags SG_READ_ONLY + ## LLD doesn't support defining symbols in synthetic sections, so we test them ## via this slightly more awkward route. # RUN: llvm-readobj --section-headers %t/ydata | \ diff --git a/llvm/include/llvm/BinaryFormat/MachO.h b/llvm/include/llvm/BinaryFormat/MachO.h --- a/llvm/include/llvm/BinaryFormat/MachO.h +++ b/llvm/include/llvm/BinaryFormat/MachO.h @@ -107,6 +107,7 @@ SG_FVMLIB = 0x2u, SG_NORELOC = 0x4u, SG_PROTECTED_VERSION_1 = 0x8u, + SG_READ_ONLY = 0x10u, // Constant masks for the "flags" field in llvm::MachO::section and // llvm::MachO::section_64 diff --git a/llvm/tools/llvm-objdump/MachODump.cpp b/llvm/tools/llvm-objdump/MachODump.cpp --- a/llvm/tools/llvm-objdump/MachODump.cpp +++ b/llvm/tools/llvm-objdump/MachODump.cpp @@ -8858,6 +8858,12 @@ outs() << " PROTECTED_VERSION_1"; flags &= ~MachO::SG_PROTECTED_VERSION_1; } + if (flags & MachO::SG_READ_ONLY) { + // Apple's otool prints the SG_ prefix for this flag, but not for the + // others. + outs() << " SG_READ_ONLY"; + flags &= ~MachO::SG_READ_ONLY; + } if (flags) outs() << format(" 0x%08" PRIx32, flags) << " (unknown flags)\n"; else