Skip to content

Commit

Permalink
Promote weak undefs to dynamic symbols if building DSO
Browse files Browse the repository at this point in the history
475a250 changed mold's behavior on
weak undefined symbols, so that if they are not resolved within the
current ELF module, they are resolved to address zero. Previously,
they would be promoted to dynamic symbols to give then another chance
to be resolved at runtime.

That change caused a regression in Firefox. Firefox uses weak undef
symbols as a mean to export symbols from libxul.so. Quote from
Firefox's mfbt/Types.h:

> On linux mozglue is linked in the program and we link libxul.so with
> -z,defs. Normally that causes the linker to reject undefined references in
> libxul.so, but as a loophole it allows undefined references to weak
> symbols. We add the weak attribute to the import version of the MFBT API
> macros to exploit this.

So, they use this as a "loophole".

This change partially revert 475a250.
Now, remaining weak undefs are resolved to address zero only when we
are creating an executable.

Fixes #114
  • Loading branch information
rui314 committed Sep 6, 2021
1 parent c21302e commit b39a47a
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 41 deletions.
14 changes: 11 additions & 3 deletions elf/object-file.cc
Original file line number Diff line number Diff line change
Expand Up @@ -976,8 +976,6 @@ void ObjectFile<E>::claim_unresolved_symbols(Context<E> &ctx) {
if (!this->is_alive)
return;

bool claim_all = ctx.arg.shared && !ctx.arg.z_defs;

for (i64 i = first_global; i < this->symbols.size(); i++) {
const ElfSym<E> &esym = elf_syms[i];
Symbol<E> &sym = *this->symbols[i];
Expand All @@ -1000,7 +998,17 @@ void ObjectFile<E>::claim_unresolved_symbols(Context<E> &ctx) {

if (!sym.file ||
(sym.esym().is_undef() && sym.file->priority < this->priority)) {
if (claim_all) {
// Traditionally, remaining undefined symbols cause a link failure
// only when we are creating an executable. Undefined symbols in
// shared objects are promoted to dynamic symbols, so that they'll
// get another chance to be resolved at run-time. You can change the
// behavior by passing `-z defs` to the linker.
//
// Even if `-z defs` is given, weak undefined symbols are still
// promoted to dynamic symbols for compatibility with other linkers.
// Some major programs, notably Firefox, depend on the behavior
// (they use this loophole to export symbols from libxul.so).
if (ctx.arg.shared && (!ctx.arg.z_defs || esym.is_undef_weak())) {
// Convert remaining undefined symbols to dynamic symbols.
claim(!ctx.arg.is_static);
if (sym.traced)
Expand Down
25 changes: 25 additions & 0 deletions test/weak-export-dso.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/bin/bash
set -e
cd $(dirname $0)
mold=`pwd`/../mold
echo -n "Testing $(basename -s .sh $0) ... "
t=$(pwd)/tmp/$(basename -s .sh $0)
mkdir -p $t

cat <<EOF | cc -fPIC -c -o $t/a.o -xc -
#include <stdio.h>
__attribute__((weak)) int foo();
int main() {
printf("%d\n", foo ? foo() : 3);
}
EOF

clang -fuse-ld=$mold -o $t/b.so $t/a.o -shared
clang -fuse-ld=$mold -o $t/c.so $t/a.o -shared -Wl,-z,defs

readelf --dyn-syms $t/b.so | grep -q 'WEAK DEFAULT UND foo'
readelf --dyn-syms $t/c.so | grep -q 'WEAK DEFAULT UND foo'

echo OK
23 changes: 23 additions & 0 deletions test/weak-export-exe.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/bin/bash
set -e
cd $(dirname $0)
mold=`pwd`/../mold
echo -n "Testing $(basename -s .sh $0) ... "
t=$(pwd)/tmp/$(basename -s .sh $0)
mkdir -p $t

cat <<EOF | cc -fPIC -c -o $t/a.o -xc -
#include <stdio.h>
__attribute__((weak)) int foo();
int main() {
printf("%d\n", foo ? foo() : 3);
}
EOF

clang -fuse-ld=$mold -o $t/exe $t/a.o
! readelf --dyn-syms $t/exe | grep -q 'WEAK DEFAULT UND foo' || false
$t/exe | grep -q '^3$'

echo OK
38 changes: 0 additions & 38 deletions test/weak-export.sh

This file was deleted.

0 comments on commit b39a47a

Please sign in to comment.