musl: ldso/dlsym: fix mips returning undef dlsym
[openwrt/staging/981213.git] / toolchain / musl / patches / 020-make-relocation-time-symbol-lookup-and-dlsym-consistent.patch
1 >From a57cd35acf26ba6202ed6534a57f496464f431a1 Mon Sep 17 00:00:00 2001
2 From: Szabolcs Nagy <nsz@port70.net>
3 Date: Sat, 10 Aug 2019 23:14:40 +0000
4 Subject: [PATCH] make relocation time symbol lookup and dlsym consistent
5
6 Using common code path for all symbol lookups fixes three dlsym issues:
7
8 - st_shndx of STT_TLS symbols were not checked and thus an undefined
9 tls symbol reference could be incorrectly treated as a definition
10 (the sysv hash lookup returns undefined symbols, gnu does not, so should
11 be rare in practice).
12
13 - symbol binding was not checked so a hidden symbol may be returned
14 (in principle STB_LOCAL symbols may appear in the dynamic symbol table
15 for hidden symbols, but linkers most likely don't produce it).
16
17 - mips specific behaviour was not applied (ARCH_SYM_REJECT_UND) so
18 undefined symbols may be returned on mips.
19
20 always_inline is used to avoid relocation performance regression, the
21 code generation for find_sym should not be affected.
22
23 BAckported to 1.1.19
24
25 ---
26 ldso/dynlink.c | 84 +++++++++++++++++++-------------------------------
27 1 file changed, 31 insertions(+), 53 deletions(-)
28
29 --- a/ldso/dynlink.c
30 +++ b/ldso/dynlink.c
31 @@ -257,12 +257,16 @@ static Sym *gnu_lookup_filtered(uint32_t
32 #define ARCH_SYM_REJECT_UND(s) 0
33 #endif
34
35 -static struct symdef find_sym(struct dso *dso, const char *s, int need_def)
36 +#if defined(__GNUC__)
37 +__attribute__((always_inline))
38 +#endif
39 +static inline struct symdef find_sym2(struct dso *dso, const char *s, int need_def, int use_deps)
40 {
41 uint32_t h = 0, gh = gnu_hash(s), gho = gh / (8*sizeof(size_t)), *ght;
42 size_t ghm = 1ul << gh % (8*sizeof(size_t));
43 struct symdef def = {0};
44 - for (; dso; dso=dso->syms_next) {
45 + struct dso **deps = use_deps ? dso->deps : 0;
46 + for (; dso; dso=use_deps ? *deps++ : dso->syms_next) {
47 Sym *sym;
48 if ((ght = dso->ghashtab)) {
49 sym = gnu_lookup_filtered(gh, ght, dso, s, gho, ghm);
50 @@ -290,6 +294,11 @@ static struct symdef find_sym(struct dso
51 __attribute__((__visibility__("hidden")))
52 ptrdiff_t __tlsdesc_static(), __tlsdesc_dynamic();
53
54 +static struct symdef find_sym(struct dso *dso, const char *s, int need_def)
55 +{
56 + return find_sym2(dso, s, need_def, 0);
57 +}
58 +
59 static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stride)
60 {
61 unsigned char *base = dso->base;
62 @@ -1872,58 +1881,27 @@ void *__tls_get_addr(tls_mod_off_t *);
63
64 static void *do_dlsym(struct dso *p, const char *s, void *ra)
65 {
66 - size_t i;
67 - uint32_t h = 0, gh = 0, *ght;
68 - Sym *sym;
69 - if (p == head || p == RTLD_DEFAULT || p == RTLD_NEXT) {
70 - if (p == RTLD_DEFAULT) {
71 - p = head;
72 - } else if (p == RTLD_NEXT) {
73 - p = addr2dso((size_t)ra);
74 - if (!p) p=head;
75 - p = p->next;
76 - }
77 - struct symdef def = find_sym(p, s, 0);
78 - if (!def.sym) goto failed;
79 - if ((def.sym->st_info&0xf) == STT_TLS)
80 - return __tls_get_addr((tls_mod_off_t []){def.dso->tls_id, def.sym->st_value});
81 - if (DL_FDPIC && (def.sym->st_info&0xf) == STT_FUNC)
82 - return def.dso->funcdescs + (def.sym - def.dso->syms);
83 - return laddr(def.dso, def.sym->st_value);
84 - }
85 - if (__dl_invalid_handle(p))
86 + int use_deps = 0;
87 + if (p == head || p == RTLD_DEFAULT) {
88 + p = head;
89 + } else if (p == RTLD_NEXT) {
90 + p = addr2dso((size_t)ra);
91 + if (!p) p=head;
92 + p = p->next;
93 + } else if (__dl_invalid_handle(p)) {
94 + return 0;
95 + } else
96 + use_deps = 1;
97 + struct symdef def = find_sym2(p, s, 0, use_deps);
98 + if (!def.sym) {
99 + error("Symbol not found: %s", s);
100 return 0;
101 - if ((ght = p->ghashtab)) {
102 - gh = gnu_hash(s);
103 - sym = gnu_lookup(gh, ght, p, s);
104 - } else {
105 - h = sysv_hash(s);
106 - sym = sysv_lookup(s, h, p);
107 }
108 - if (sym && (sym->st_info&0xf) == STT_TLS)
109 - return __tls_get_addr((tls_mod_off_t []){p->tls_id, sym->st_value});
110 - if (DL_FDPIC && sym && sym->st_shndx && (sym->st_info&0xf) == STT_FUNC)
111 - return p->funcdescs + (sym - p->syms);
112 - if (sym && sym->st_value && (1<<(sym->st_info&0xf) & OK_TYPES))
113 - return laddr(p, sym->st_value);
114 - for (i=0; p->deps[i]; i++) {
115 - if ((ght = p->deps[i]->ghashtab)) {
116 - if (!gh) gh = gnu_hash(s);
117 - sym = gnu_lookup(gh, ght, p->deps[i], s);
118 - } else {
119 - if (!h) h = sysv_hash(s);
120 - sym = sysv_lookup(s, h, p->deps[i]);
121 - }
122 - if (sym && (sym->st_info&0xf) == STT_TLS)
123 - return __tls_get_addr((tls_mod_off_t []){p->deps[i]->tls_id, sym->st_value});
124 - if (DL_FDPIC && sym && sym->st_shndx && (sym->st_info&0xf) == STT_FUNC)
125 - return p->deps[i]->funcdescs + (sym - p->deps[i]->syms);
126 - if (sym && sym->st_value && (1<<(sym->st_info&0xf) & OK_TYPES))
127 - return laddr(p->deps[i], sym->st_value);
128 - }
129 -failed:
130 - error("Symbol not found: %s", s);
131 - return 0;
132 + if ((def.sym->st_info&0xf) == STT_TLS)
133 + return __tls_get_addr((tls_mod_off_t []){def.dso->tls_id, def.sym->st_value-DTP_OFFSET});
134 + if (DL_FDPIC && (def.sym->st_info&0xf) == STT_FUNC)
135 + return def.dso->funcdescs + (def.sym - def.dso->syms);
136 + return laddr(def.dso, def.sym->st_value);
137 }
138
139 int dladdr(const void *addr, Dl_info *info)