diff --git a/input_sections.cc b/input_sections.cc index af71bf84..228388d6 100644 --- a/input_sections.cc +++ b/input_sections.cc @@ -148,7 +148,11 @@ void InputSection::scan_relocations() { for (int i = 0; i < rels.size(); i++) { const ELF64LE::Rela &rel = rels[i]; Symbol &sym = *file->symbols[rel.getSymbol(false)]; - assert(sym.file); + + if (!sym.file || sym.is_placeholder) { + file->has_error = true; + continue; + } switch (rel.getType(false)) { case R_X86_64_NONE: @@ -207,6 +211,18 @@ void InputSection::scan_relocations() { } } +void InputSection::report_undefined_symbols() { + if (!(shdr.sh_flags & SHF_ALLOC)) + return; + + for (const ELF64LE::Rela &rel : rels) { + Symbol &sym = *file->symbols[rel.getSymbol(false)]; + if (!sym.file || sym.is_placeholder) + llvm::errs() << "undefined symbol: " << toString(file) + << ": " << sym.name << "\n"; + } +} + MergeableSection::MergeableSection(InputSection *isec, ArrayRef contents) : InputChunk(MERGEABLE, isec->file, isec->shdr, isec->name), parent(*MergedSection::get_instance(isec->name, isec->shdr.sh_flags, diff --git a/main.cc b/main.cc index 462aea53..a1872693 100644 --- a/main.cc +++ b/main.cc @@ -301,50 +301,34 @@ static void bin_sections() { }); } -static void check_undefined_symbols() { +static void check_duplicate_symbols() { MyTimer t("check_undef_syms", before_copy_timer); - std::vector has_errors(out::objs.size()); - tbb::parallel_for(0, (int)out::objs.size(), [&](int i) { - ObjectFile *file = out::objs[i]; - if (!file->is_alive || file->is_dso) + tbb::parallel_for_each(out::objs, [](ObjectFile *file) { + if (!file->is_alive) return; - for (int j = file->first_global; j < file->elf_syms.size(); j++) { - const ELF64LE::Sym &esym = file->elf_syms[j]; - Symbol &sym = *file->symbols[j]; + for (int i = file->first_global; i < file->elf_syms.size(); i++) { + const ELF64LE::Sym &esym = file->elf_syms[i]; + Symbol &sym = *file->symbols[i]; bool is_weak = (esym.getBinding() == STB_WEAK); - if (esym.isUndefined() && !is_weak && (!sym.file || sym.is_placeholder)) { - has_errors[i] = true; - return; - } - if (esym.isDefined() && !is_weak && sym.file != file) { - has_errors[i] = true; + file->has_error = true; return; } } }); - bool has_error = false; - - for (int i = 0; i < out::objs.size(); i++) { - if (!has_errors[i]) + for (ObjectFile *file : out::objs) { + if (!file->has_error) continue; - has_error = true; - ObjectFile *file = out::objs[i]; - - for (int j = file->first_global; j < file->elf_syms.size(); j++) { - const ELF64LE::Sym &esym = file->elf_syms[j]; - Symbol &sym = *file->symbols[j]; + for (int i = file->first_global; i < file->elf_syms.size(); i++) { + const ELF64LE::Sym &esym = file->elf_syms[i]; + Symbol &sym = *file->symbols[i]; bool is_weak = (esym.getBinding() == STB_WEAK); - if (esym.isUndefined() && !is_weak && (!sym.file || sym.is_placeholder)) - llvm::errs() << "undefined symbol: " << toString(file) - << ": " << sym.name << "\n"; - if (esym.isDefined() && !is_weak && sym.file != file) llvm::errs() << "duplicate symbol: " << toString(file) << ": " << toString(sym.file) << ": " @@ -352,8 +336,9 @@ static void check_undefined_symbols() { } } - if (has_error) - exit(1); + for (ObjectFile *file : out::objs) + if (file->has_error) + _exit(1); } static void set_isec_offsets() { @@ -407,6 +392,16 @@ static void scan_rels() { isec->scan_relocations(); }); + for (ObjectFile *file : out::objs) + if (file->has_error) + for (InputSection *isec : file->sections) + if (isec) + isec->report_undefined_symbols(); + + for (ObjectFile *file : out::objs) + if (file->has_error) + _exit(1); + std::vector files; files.insert(files.end(), out::objs.begin(), out::objs.end()); files.insert(files.end(), out::dsos.begin(), out::dsos.end()); @@ -876,9 +871,6 @@ int main(int argc, char **argv) { // Beyond this point, no new symbols will be added to the result. - // Make sure that all symbols have been resolved. - check_undefined_symbols(); - // Copy shared object name strings to .dynsym for (SharedFile *file : out::dsos) out::dynstr->add_string(file->soname); @@ -896,6 +888,9 @@ int main(int argc, char **argv) { if (out::chunks[i]->kind != OutputChunk::HEADER) out::chunks[i]->shndx = shndx++; + // Make sure that all symbols have been resolved. + check_duplicate_symbols(); + // Scan relocations to fix the sizes of .got, .plt, .got.plt, .dynstr, // .rela.dyn, .rela.plt. scan_rels(); diff --git a/mold.h b/mold.h index bed5ca86..7bfd2086 100644 --- a/mold.h +++ b/mold.h @@ -261,7 +261,6 @@ class InputChunk { public: enum Kind : u8 { REGULAR, MERGEABLE }; - virtual void scan_relocations() {} virtual void copy_buf() {} u64 get_addr() const; @@ -283,7 +282,8 @@ public: : InputChunk(REGULAR, file, shdr, name) {} void copy_buf() override; - void scan_relocations() override; + void scan_relocations(); + void report_undefined_symbols(); ArrayRef rels; std::vector rel_pieces; @@ -732,6 +732,7 @@ public: ArrayRef elf_syms; int first_global = 0; const bool is_in_archive; + std::atomic_bool has_error = ATOMIC_VAR_INIT(false); u64 local_symtab_size = 0; u64 local_strtab_size = 0; diff --git a/object_file.cc b/object_file.cc index 5b9c806c..d305ee47 100644 --- a/object_file.cc +++ b/object_file.cc @@ -519,6 +519,7 @@ void ObjectFile::handle_undefined_weak_symbols() { sym.value = 0; sym.visibility = esym.getVisibility(); sym.esym = &esym; + sym.is_placeholder = false; sym.is_undef_weak = true; sym.is_imported = false; diff --git a/test/duplicate-error.s b/test/duplicate-error.s new file mode 100644 index 00000000..ee070bc9 --- /dev/null +++ b/test/duplicate-error.s @@ -0,0 +1,8 @@ +// RUN: cc -o %t.o -c %s +// RUN: not mold -o %t.exe %t.o %t.o 2> %t.log +// RUN: grep 'duplicate symbol: .*\.o: .*\.o: main' %t.log + + .text + .globl main +main: + nop diff --git a/test/missing-but-ok.s b/test/missing-but-ok.s new file mode 100644 index 00000000..617b7371 --- /dev/null +++ b/test/missing-but-ok.s @@ -0,0 +1,7 @@ +// RUN: cc -o %t.o -c %s +// RUN: mold -o %t.exe %t.o + + .text + .globl _start, foo +_start: + nop diff --git a/test/missing-error.s b/test/missing-error.s new file mode 100644 index 00000000..46be01a2 --- /dev/null +++ b/test/missing-error.s @@ -0,0 +1,8 @@ +// RUN: cc -o %t.o -c %s +// RUN: not mold -o %t.exe %t.o 2> %t.log +// RUN: grep 'undefined symbol: .*\.o: foo' %t.log + + .text + .globl main +main: + call foo