Skip to content

Commit af396ad

Browse files
committed
Add --audit and --depaudit
These are for the sake of compatibility with GNU ld.
1 parent a2ee737 commit af396ad

File tree

10 files changed

+146
-11
lines changed

10 files changed

+146
-11
lines changed

src/cmdline.cc

+13
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ static const char helpmsg[] = R"(
4141
-N, --omagic Do not page align data; do not make text readonly
4242
--no-omagic
4343
-O NUMBER Ignored
44+
-P AUDITLIB, --depaudit AUDITLIB
45+
Set DT_DEPAUDIT to the specified value
4446
-S, --strip-debug Strip .debug_* sections
4547
-T FILE, --script FILE Read linker script
4648
-X, --discard-locals Discard temporary local symbols
@@ -76,6 +78,7 @@ static const char helpmsg[] = R"(
7678
--no-apply-dynamic-relocs
7779
--as-needed Only set DT_NEEDED if used
7880
--no-as-needed
81+
--audit LIBNAME Set DT_AUDIT to the specified value
7982
--build-id [none,md5,sha1,sha256,fast,uuid,HEXSTRING]
8083
Generate build ID
8184
--no-build-id
@@ -892,6 +895,16 @@ std::vector<std::string> parse_nonpositional_args(Context<E> &ctx) {
892895
}
893896
} else if (read_arg("soname") || read_arg("h")) {
894897
ctx.arg.soname = arg;
898+
} else if (read_arg("audit")) {
899+
if (ctx.arg.audit.empty())
900+
ctx.arg.audit = arg;
901+
else
902+
ctx.arg.audit += ":" + std::string(arg);
903+
} else if (read_arg("depaudit") || read_arg("P")) {
904+
if (ctx.arg.depaudit.empty())
905+
ctx.arg.depaudit = arg;
906+
else
907+
ctx.arg.depaudit += ":" + std::string(arg);
895908
} else if (read_flag("allow-multiple-definition")) {
896909
ctx.arg.allow_multiple_definition = true;
897910
} else if (read_flag("apply-dynamic-relocs")) {

src/elf.h

+2
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,8 @@ enum : u32 {
285285
DT_RELR = 36,
286286
DT_RELRENT = 37,
287287
DT_GNU_HASH = 0x6ffffef5,
288+
DT_DEPAUDIT = 0x6ffffefb,
289+
DT_AUDIT = 0x6ffffefc,
288290
DT_VERSYM = 0x6ffffff0,
289291
DT_RELACOUNT = 0x6ffffff9,
290292
DT_RELCOUNT = 0x6ffffffa,

src/input-files.cc

+15
Original file line numberDiff line numberDiff line change
@@ -1319,6 +1319,21 @@ std::vector<std::string_view> SharedFile<E>::get_dt_needed(Context<E> &ctx) {
13191319
return vec;
13201320
}
13211321

1322+
template <typename E>
1323+
std::string_view SharedFile<E>::get_dt_audit(Context<E> &ctx) {
1324+
ElfShdr<E> *sec = this->find_section(SHT_DYNAMIC);
1325+
if (!sec)
1326+
return "";
1327+
1328+
std::span<ElfDyn<E>> dynamic = this->template get_data<ElfDyn<E>>(ctx, *sec);
1329+
std::string_view strtab = this->get_string(ctx, sec->sh_link);
1330+
1331+
for (ElfDyn<E> &dyn : dynamic)
1332+
if (dyn.d_tag == DT_AUDIT)
1333+
return strtab.data() + dyn.d_val;
1334+
return "";
1335+
}
1336+
13221337
// Symbol versioning is a GNU extension to the ELF file format. I don't
13231338
// particularly like the feature as it complicates the semantics of
13241339
// dynamic linking, but we need to support it anyway because it is

src/main.cc

+1-10
Original file line numberDiff line numberDiff line change
@@ -480,16 +480,7 @@ int mold_main(int argc, char **argv) {
480480
shuffle_sections(ctx);
481481

482482
// Copy string referred by .dynamic to .dynstr.
483-
for (SharedFile<E> *file : ctx.dsos)
484-
ctx.dynstr->add_string(file->soname);
485-
for (std::string_view str : ctx.arg.auxiliary)
486-
ctx.dynstr->add_string(str);
487-
for (std::string_view str : ctx.arg.filter)
488-
ctx.dynstr->add_string(str);
489-
if (!ctx.arg.rpaths.empty())
490-
ctx.dynstr->add_string(ctx.arg.rpaths);
491-
if (!ctx.arg.soname.empty())
492-
ctx.dynstr->add_string(ctx.arg.soname);
483+
add_dynamic_strings(ctx);
493484

494485
if constexpr (is_ppc64v1<E>)
495486
ppc64v1_scan_symbols(ctx);

src/mold.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -1476,6 +1476,7 @@ class SharedFile : public InputFile<E> {
14761476
std::span<Symbol<E> *> get_symbols_at(Symbol<E> *sym);
14771477
i64 get_alignment(Symbol<E> *sym);
14781478
std::vector<std::string_view> get_dt_needed(Context<E> &ctx);
1479+
std::string_view get_dt_audit(Context<E> &ctx);
14791480
bool is_readonly(Symbol<E> *sym);
14801481

14811482
void mark_live_objects(Context<E> &ctx,
@@ -1678,6 +1679,7 @@ template <typename E> void sort_init_fini(Context<E> &);
16781679
template <typename E> void sort_ctor_dtor(Context<E> &);
16791680
template <typename E> void fixup_ctors_in_init_array(Context<E> &);
16801681
template <typename E> void shuffle_sections(Context<E> &);
1682+
template <typename E> void add_dynamic_strings(Context<E> &);
16811683
template <typename E> void compute_section_sizes(Context<E> &);
16821684
template <typename E> void sort_output_sections(Context<E> &);
16831685
template <typename E> void claim_unresolved_symbols(Context<E> &);
@@ -2039,8 +2041,11 @@ struct Context {
20392041
i64 z_stack_size = 0;
20402042
std::optional<Glob> unique;
20412043
std::optional<u64> physical_image_base;
2044+
std::optional<std::vector<Symbol<E> *>> retain_symbols_file;
20422045
std::string Map;
2046+
std::string audit;
20432047
std::string chroot;
2048+
std::string depaudit;
20442049
std::string dependency_file;
20452050
std::string directory;
20462051
std::string dynamic_linker;
@@ -2052,7 +2057,6 @@ struct Context {
20522057
std::string soname;
20532058
std::string sysroot;
20542059
std::string_view emulation;
2055-
std::optional<std::vector<Symbol<E> *>> retain_symbols_file;
20562060
std::unordered_map<std::string_view, u64> section_align;
20572061
std::unordered_map<std::string_view, u64> section_start;
20582062
std::unordered_set<std::string_view> discard_section;

src/output-chunks.cc

+6
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,12 @@ static std::vector<Word<E>> create_dynamic_section(Context<E> &ctx) {
655655
for (std::string_view str : ctx.arg.auxiliary)
656656
define(DT_AUXILIARY, ctx.dynstr->find_string(str));
657657

658+
if (!ctx.arg.audit.empty())
659+
define(DT_AUDIT, ctx.dynstr->find_string(ctx.arg.audit));
660+
661+
if (!ctx.arg.depaudit.empty())
662+
define(DT_DEPAUDIT, ctx.dynstr->find_string(ctx.arg.depaudit));
663+
658664
for (std::string_view str : ctx.arg.filter)
659665
define(DT_FILTER, ctx.dynstr->find_string(str));
660666

src/passes.cc

+31
Original file line numberDiff line numberDiff line change
@@ -1367,6 +1367,36 @@ void shuffle_sections(Context<E> &ctx) {
13671367
}
13681368
}
13691369

1370+
template <typename E>
1371+
void add_dynamic_strings(Context<E> &ctx) {
1372+
for (SharedFile<E> *file : ctx.dsos) {
1373+
std::string s = std::string(file->get_dt_audit(ctx));
1374+
if (!s.empty()) {
1375+
if (ctx.arg.depaudit.empty())
1376+
ctx.arg.depaudit = s;
1377+
else
1378+
ctx.arg.depaudit += ":" + s;
1379+
}
1380+
}
1381+
1382+
auto add = [&](std::string_view s) {
1383+
if (!s.empty())
1384+
ctx.dynstr->add_string(s);
1385+
};
1386+
1387+
for (SharedFile<E> *file : ctx.dsos)
1388+
add(file->soname);
1389+
for (std::string_view str : ctx.arg.auxiliary)
1390+
add(str);
1391+
for (std::string_view str : ctx.arg.filter)
1392+
add(str);
1393+
1394+
add(ctx.arg.audit);
1395+
add(ctx.arg.depaudit);
1396+
add(ctx.arg.rpaths);
1397+
add(ctx.arg.soname);
1398+
}
1399+
13701400
template <typename E>
13711401
void compute_section_sizes(Context<E> &ctx) {
13721402
Timer t(ctx, "compute_section_sizes");
@@ -3360,6 +3390,7 @@ template void sort_init_fini(Context<E> &);
33603390
template void sort_ctor_dtor(Context<E> &);
33613391
template void fixup_ctors_in_init_array(Context<E> &);
33623392
template void shuffle_sections(Context<E> &);
3393+
template void add_dynamic_strings(Context<E> &);
33633394
template void compute_section_sizes(Context<E> &);
33643395
template void sort_output_sections(Context<E> &);
33653396
template void claim_unresolved_symbols(Context<E> &);

test/audit.sh

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#!/bin/bash
2+
. $(dirname $0)/common.inc
3+
4+
cat <<EOF | $CC -o $t/a.o -c -xc -
5+
int main() {}
6+
EOF
7+
8+
$CC -B. -o $t/exe1 $t/a.o
9+
readelf --dynamic $t/exe1 | not grep 'Audit library'
10+
11+
$CC -B. -o $t/exe2 $t/a.o -Wl,--audit=foo
12+
readelf --dynamic $t/exe2 | grep -F 'Audit library: [foo]'
13+
14+
$CC -B. -o $t/exe3 $t/a.o -Wl,--audit=foo -Wl,--audit=bar
15+
readelf --dynamic $t/exe3 | grep -F 'Audit library: [foo:bar]'
16+
17+
18+
cat <<'EOF' | $CC -B. -shared -o $t/b.so -xc - -fPIC
19+
#include <stdio.h>
20+
unsigned la_version(unsigned v) {
21+
fprintf(stderr, "version=%d\n", v);
22+
return 0;
23+
}
24+
EOF
25+
26+
LD_AUDIT=$t/b.so $QEMU $t/exe1 |& grep 'version=' || skip
27+
28+
$CC -B. -o $t/exe4 $t/a.o -Wl,--audit=$t/b.so
29+
$QEMU $t/exe4 |& grep 'version='

test/depaudit.sh

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/bin/bash
2+
. $(dirname $0)/common.inc
3+
4+
cat <<EOF | $CC -o $t/a.o -c -xc -
5+
int main() {}
6+
EOF
7+
8+
$CC -B. -o $t/exe1 $t/a.o
9+
readelf --dynamic $t/exe1 | not grep 'Dependency audit library'
10+
11+
$CC -B. -o $t/exe2 $t/a.o -Wl,--depaudit=libdepaudit.so
12+
readelf --dynamic $t/exe2 | grep -F 'Dependency audit library: [libdepaudit.so]'
13+
14+
$CC -B. -o $t/exe3 $t/a.o -Wl,--depaudit=foo -Wl,-P,bar
15+
readelf --dynamic $t/exe3 | grep -F 'Dependency audit library: [foo:bar]'

test/depaudit2.sh

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#!/bin/bash
2+
. $(dirname $0)/common.inc
3+
4+
cat <<'EOF' | $CC -B. -shared -o $t/a.so -xc - -fPIC
5+
#include <stdio.h>
6+
7+
unsigned la_version(unsigned v) {
8+
fprintf(stderr, "version=%d\n", v);
9+
return 0;
10+
}
11+
12+
void foo() {}
13+
EOF
14+
15+
cat <<'EOF' | $CC -B. -shared -o $t/b.so -xc - -fPIC -Wl,--audit=$t/a.so
16+
void foo();
17+
void bar() { foo(); }
18+
EOF
19+
20+
cat <<'EOF' | $CC -c -o $t/c.o -xc -
21+
void bar();
22+
int main() { bar(); }
23+
EOF
24+
25+
$CC -B. -o $t/exe1 $t/c.o $t/b.so
26+
readelf --dynamic $t/exe1 | grep 'Dependency audit library:..*/a.so'
27+
28+
$CC -B. -o $t/exe2 $t/c.o $t/b.so -Wl,--depaudit=foo
29+
readelf --dynamic $t/exe2 | grep 'Dependency audit library:..*foo:.*/a.so'

0 commit comments

Comments
 (0)