diff --git a/lld/ELF/Compartments.cpp b/lld/ELF/Compartments.cpp index c9e6874699e08..7d87133dbe92e 100644 --- a/lld/ELF/Compartments.cpp +++ b/lld/ELF/Compartments.cpp @@ -479,21 +479,60 @@ void assignSectionsToCompartments() { assert(s->file->compartment == 0); StringRef path = s->file->getName(); - Expected c = fileLookup.findMatch(path); - if (!c) { - error("input file " + path + " " + toString(c.takeError())); - valid = false; - continue; + StringRef scope = s->file->archiveName; + StringRef scopedPath = path; + std::string scopedStr; + if (!scope.empty()) { + scopedStr = (scope + ":" + path).str(); + scopedPath = scopedStr; } - - // If the path is not a basename, try to match on the basename. - if (c->isDefault() && llvm::sys::path::has_parent_path(path)) { - c = fileLookup.findMatch(llvm::sys::path::filename(path)); + Expected c = *defaultCompart; + handleAllErrors(c.takeError()); + auto tryMatch = [&](StringRef s) -> bool { + llvm::errs() << "tryMatch: " << s << "\n"; + c = fileLookup.findMatch(s); if (!c) { - error("input file " + path + " " + toString(c.takeError())); + error("input file " + scopedPath + " " + toString(c.takeError())); valid = false; + return false; + } + return true; + }; + + // When matching, give precedence to full-path matches for the archive + // name (for archive members) or file name (for standalone input files). + + // For archive members, require the pattern to include the name of the + // archive with an optional colon-prefixed suffix of the member name. + if (!scope.empty()) { + // First, try to match a fully scoped :. + if (!tryMatch(scopedPath)) + continue; + + // Second, match on just the archive name. + if (c->isDefault() && !tryMatch(scope)) continue; + + // If the archive path is not a basename, try to match with a scope of + // just the basename. + if (c->isDefault() && llvm::sys::path::has_parent_path(scope)) { + StringRef baseScope = llvm::sys::path::filename(scope); + if (!tryMatch((baseScope + ":" + path).str())) + continue; + + // Try to match just the archive basename. + if (c->isDefault() && !tryMatch(baseScope)) + continue; } + } else { + // Prioritise matches with a full path. + if (c->isDefault() && !tryMatch(path)) + continue; + + // If the path is not a basename, try to match on the basename. + if (c->isDefault() && llvm::sys::path::has_parent_path(path) && + !tryMatch(llvm::sys::path::filename(path))) + continue; } if (c->isDefault()) @@ -501,7 +540,7 @@ void assignSectionsToCompartments() { s->file->compartment = c->getNumber(); if (config->verboseCompartmentalization) - message("info: input file " + s->file->getName() + " matched to " + + message("info: input file " + scopedPath + " matched to " + compartmentName(*c)); } diff --git a/lld/test/ELF/cheri/riscv/c18n/static-lib.s b/lld/test/ELF/cheri/riscv/c18n/static-lib.s new file mode 100644 index 0000000000000..7dd5ca4258db5 --- /dev/null +++ b/lld/test/ELF/cheri/riscv/c18n/static-lib.s @@ -0,0 +1,79 @@ +# REQUIRES: riscv + +# RUN: rm -rf %t && split-file %s %t + +# RUN: %riscv64_cheri_purecap_llvm-mc -filetype=obj %t/a.s -o %t/a.o +# RUN: %riscv64_cheri_purecap_llvm-mc -filetype=obj %t/b.s -o %t/b.o +# RUN: llvm-ar crs %t/libb.a %t/b.o +# RUN: ld.lld -o %t/fully-scoped %t/a.o %t/libb.a \ +# RUN: --compartment-policy=%t/fully-scoped.json +# RUN: ld.lld -o %t/scope-only %t/a.o %t/libb.a \ +# RUN: --compartment-policy=%t/scope-only.json +# RUN: not ld.lld -o %t/unscoped %t/a.o %t/libb.a \ +# RUN: --compartment-policy=%t/unscoped.json 2>&1 | \ +# RUN: FileCheck %s --check-prefix=UNSCOPED +# RUN: llvm-readelf -l %t/fully-scoped | FileCheck %s --check-prefix=SCOPED +# RUN: llvm-readelf -l %t/scope-only | FileCheck %s --check-prefix=SCOPED + +# SCOPED-LABEL: Program Headers: +# SCOPED-NEXT: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align +# SCOPED-NEXT: PHDR 0x000040 0x0000000000010040 0x0000000000010040 0x000150 0x000150 R 0x8 +# SCOPED-NEXT: LOAD 0x000000 0x0000000000010000 0x0000000000010000 0x000195 0x000195 R 0x1000 +# SCOPED-NEXT: LOAD 0x000198 0x0000000000011198 0x0000000000011198 0x00000c 0x00000c R E 0x1000 +# SCOPED-NEXT: C18N_NAME 0x000198 0x0000000000011198 0x0000000000000001 0x00000c 0x00000c 0x4 +# SCOPED-NEXT: [Compartment: one] +# SCOPED-NEXT: CHERI_PCC 0x000198 0x0000000000011198 0x0000000000011198 0x00000c 0x00000c R E 0x4 +# SCOPED-NEXT: GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x0 + +# SCOPED-LABEL: Section to Segment mapping: +# SCOPED-NEXT: Segment Sections... +# SCOPED-NEXT: 00 +# SCOPED-NEXT: 01 .c18nstrtab +# SCOPED-NEXT: 02 .text.one +# SCOPED-NEXT: 03 .text.one +# SCOPED-NEXT: 04 .text.one +# SCOPED-NEXT: 05 +# SCOPED-NEXT: None .pad.cheri.pcc.one .comment .symtab .shstrtab .strtab + +# UNSCOPED: error: no output sections for compartment one + +#--- a.s + +call foo + +#--- b.s + +.global foo +.type foo, %function +foo: + ret + +#--- fully-scoped.json + +{ + "compartments": { + "one": { + "files": ["libb.a:b.o"] + } + } +} + +#--- scope-only.json + +{ + "compartments": { + "one": { + "files": ["libb.a"] + } + } +} + +#--- unscoped.json + +{ + "compartments": { + "one": { + "files": ["b.o"] + } + } +}