Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 50 additions & 11 deletions lld/ELF/Compartments.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -479,29 +479,68 @@ void assignSectionsToCompartments() {
assert(s->file->compartment == 0);

StringRef path = s->file->getName();
Expected<Compartment &> 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<Compartment &> 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 <archive>:<member>.
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())
continue;

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));
}

Expand Down
79 changes: 79 additions & 0 deletions lld/test/ELF/cheri/riscv/c18n/static-lib.s
Original file line number Diff line number Diff line change
@@ -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"]
}
}
}
Loading