Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

sparc: Fix VDSO build with older binutils.

Older versions of bintutils do not allow symbol math across different
segments on sparc:

====================
Assembler messages:
99: Error: operation combines symbols in different segments
====================

This is controlled by whether or not DIFF_EXPR_OK is defined in
gas/config/tc-*.h and for sparc this was not the case until mid-2017.

So we have to patch between %stick and %tick another way.

Do what powerpc does and emit two versions of the relevant functions,
one using %tick and one using %stick, and patch the symbols in the
dynamic symbol table.

Fixes: 2f6c9bf31a0b ("sparc: Improve VDSO instruction patching.")
Reported-by: Meelis Roos <mroos@linux.ee>
Tested-by: Meelis Roos <mroos@linux.ee>
Signed-off-by: David S. Miller <davem@davemloft.net>

+337 -64
-2
arch/sparc/include/asm/vdso.h
··· 9 9 void *data; 10 10 unsigned long size; /* Always a multiple of PAGE_SIZE */ 11 11 12 - unsigned long tick_patch, tick_patch_len; 13 - 14 12 long sym_vvar_start; /* Negative offset to the vvar area */ 15 13 }; 16 14
+129 -20
arch/sparc/vdso/vclock_gettime.c
··· 90 90 { 91 91 u64 ret; 92 92 93 - __asm__ __volatile__("1:\n\t" 94 - "rd %%tick, %0\n\t" 95 - ".pushsection .tick_patch, \"a\"\n\t" 96 - ".word 1b - ., 1f - .\n\t" 97 - ".popsection\n\t" 98 - ".pushsection .tick_patch_replacement, \"ax\"\n\t" 99 - "1:\n\t" 100 - "rd %%asr24, %0\n\t" 101 - ".popsection\n" 102 - : "=r" (ret)); 93 + __asm__ __volatile__("rd %%tick, %0" : "=r" (ret)); 94 + return ret; 95 + } 96 + 97 + notrace static __always_inline u64 vread_tick_stick(void) 98 + { 99 + u64 ret; 100 + 101 + __asm__ __volatile__("rd %%asr24, %0" : "=r" (ret)); 103 102 return ret; 104 103 } 105 104 #else ··· 106 107 { 107 108 register unsigned long long ret asm("o4"); 108 109 109 - __asm__ __volatile__("1:\n\t" 110 - "rd %%tick, %L0\n\t" 111 - "srlx %L0, 32, %H0\n\t" 112 - ".pushsection .tick_patch, \"a\"\n\t" 113 - ".word 1b - ., 1f - .\n\t" 114 - ".popsection\n\t" 115 - ".pushsection .tick_patch_replacement, \"ax\"\n\t" 116 - "1:\n\t" 117 - "rd %%asr24, %L0\n\t" 118 - ".popsection\n" 110 + __asm__ __volatile__("rd %%tick, %L0\n\t" 111 + "srlx %L0, 32, %H0" 112 + : "=r" (ret)); 113 + return ret; 114 + } 115 + 116 + notrace static __always_inline u64 vread_tick_stick(void) 117 + { 118 + register unsigned long long ret asm("o4"); 119 + 120 + __asm__ __volatile__("rd %%asr24, %L0\n\t" 121 + "srlx %L0, 32, %H0" 119 122 : "=r" (ret)); 120 123 return ret; 121 124 } ··· 129 128 u64 cycles; 130 129 131 130 cycles = vread_tick(); 131 + v = (cycles - vvar->clock.cycle_last) & vvar->clock.mask; 132 + return v * vvar->clock.mult; 133 + } 134 + 135 + notrace static __always_inline u64 vgetsns_stick(struct vvar_data *vvar) 136 + { 137 + u64 v; 138 + u64 cycles; 139 + 140 + cycles = vread_tick_stick(); 132 141 v = (cycles - vvar->clock.cycle_last) & vvar->clock.mask; 133 142 return v * vvar->clock.mult; 134 143 } ··· 163 152 return 0; 164 153 } 165 154 155 + notrace static __always_inline int do_realtime_stick(struct vvar_data *vvar, 156 + struct timespec *ts) 157 + { 158 + unsigned long seq; 159 + u64 ns; 160 + 161 + do { 162 + seq = vvar_read_begin(vvar); 163 + ts->tv_sec = vvar->wall_time_sec; 164 + ns = vvar->wall_time_snsec; 165 + ns += vgetsns_stick(vvar); 166 + ns >>= vvar->clock.shift; 167 + } while (unlikely(vvar_read_retry(vvar, seq))); 168 + 169 + ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns); 170 + ts->tv_nsec = ns; 171 + 172 + return 0; 173 + } 174 + 166 175 notrace static __always_inline int do_monotonic(struct vvar_data *vvar, 167 176 struct timespec *ts) 168 177 { ··· 194 163 ts->tv_sec = vvar->monotonic_time_sec; 195 164 ns = vvar->monotonic_time_snsec; 196 165 ns += vgetsns(vvar); 166 + ns >>= vvar->clock.shift; 167 + } while (unlikely(vvar_read_retry(vvar, seq))); 168 + 169 + ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns); 170 + ts->tv_nsec = ns; 171 + 172 + return 0; 173 + } 174 + 175 + notrace static __always_inline int do_monotonic_stick(struct vvar_data *vvar, 176 + struct timespec *ts) 177 + { 178 + unsigned long seq; 179 + u64 ns; 180 + 181 + do { 182 + seq = vvar_read_begin(vvar); 183 + ts->tv_sec = vvar->monotonic_time_sec; 184 + ns = vvar->monotonic_time_snsec; 185 + ns += vgetsns_stick(vvar); 197 186 ns >>= vvar->clock.shift; 198 187 } while (unlikely(vvar_read_retry(vvar, seq))); 199 188 ··· 279 228 __attribute__((weak, alias("__vdso_clock_gettime"))); 280 229 281 230 notrace int 231 + __vdso_clock_gettime_stick(clockid_t clock, struct timespec *ts) 232 + { 233 + struct vvar_data *vvd = get_vvar_data(); 234 + 235 + switch (clock) { 236 + case CLOCK_REALTIME: 237 + if (unlikely(vvd->vclock_mode == VCLOCK_NONE)) 238 + break; 239 + return do_realtime_stick(vvd, ts); 240 + case CLOCK_MONOTONIC: 241 + if (unlikely(vvd->vclock_mode == VCLOCK_NONE)) 242 + break; 243 + return do_monotonic_stick(vvd, ts); 244 + case CLOCK_REALTIME_COARSE: 245 + return do_realtime_coarse(vvd, ts); 246 + case CLOCK_MONOTONIC_COARSE: 247 + return do_monotonic_coarse(vvd, ts); 248 + } 249 + /* 250 + * Unknown clock ID ? Fall back to the syscall. 251 + */ 252 + return vdso_fallback_gettime(clock, ts); 253 + } 254 + 255 + notrace int 282 256 __vdso_gettimeofday(struct timeval *tv, struct timezone *tz) 283 257 { 284 258 struct vvar_data *vvd = get_vvar_data(); ··· 338 262 int 339 263 gettimeofday(struct timeval *, struct timezone *) 340 264 __attribute__((weak, alias("__vdso_gettimeofday"))); 265 + 266 + notrace int 267 + __vdso_gettimeofday_stick(struct timeval *tv, struct timezone *tz) 268 + { 269 + struct vvar_data *vvd = get_vvar_data(); 270 + 271 + if (likely(vvd->vclock_mode != VCLOCK_NONE)) { 272 + if (likely(tv != NULL)) { 273 + union tstv_t { 274 + struct timespec ts; 275 + struct timeval tv; 276 + } *tstv = (union tstv_t *) tv; 277 + do_realtime_stick(vvd, &tstv->ts); 278 + /* 279 + * Assign before dividing to ensure that the division is 280 + * done in the type of tv_usec, not tv_nsec. 281 + * 282 + * There cannot be > 1 billion usec in a second: 283 + * do_realtime() has already distributed such overflow 284 + * into tv_sec. So we can assign it to an int safely. 285 + */ 286 + tstv->tv.tv_usec = tstv->ts.tv_nsec; 287 + tstv->tv.tv_usec /= 1000; 288 + } 289 + if (unlikely(tz != NULL)) { 290 + /* Avoid memcpy. Some old compilers fail to inline it */ 291 + tz->tz_minuteswest = vvd->tz_minuteswest; 292 + tz->tz_dsttime = vvd->tz_dsttime; 293 + } 294 + return 0; 295 + } 296 + return vdso_fallback_gettimeofday(tv, tz); 297 + }
-3
arch/sparc/vdso/vdso-layout.lds.S
··· 73 73 74 74 .text : { *(.text*) } :text =0x90909090, 75 75 76 - .tick_patch : { *(.tick_patch) } :text 77 - .tick_patch_insns : { *(.tick_patch_insns) } :text 78 - 79 76 /DISCARD/ : { 80 77 *(.discard) 81 78 *(.discard.*)
+2
arch/sparc/vdso/vdso.lds.S
··· 18 18 global: 19 19 clock_gettime; 20 20 __vdso_clock_gettime; 21 + __vdso_clock_gettime_stick; 21 22 gettimeofday; 22 23 __vdso_gettimeofday; 24 + __vdso_gettimeofday_stick; 23 25 local: *; 24 26 }; 25 27 }
+1 -16
arch/sparc/vdso/vdso2c.h
··· 17 17 unsigned long mapping_size; 18 18 int i; 19 19 unsigned long j; 20 - ELF(Shdr) *symtab_hdr = NULL, *strtab_hdr, *secstrings_hdr, 21 - *patch_sec = NULL; 20 + ELF(Shdr) *symtab_hdr = NULL, *strtab_hdr; 22 21 ELF(Ehdr) *hdr = (ELF(Ehdr) *)raw_addr; 23 22 ELF(Dyn) *dyn = 0, *dyn_end = 0; 24 - const char *secstrings; 25 23 INT_BITS syms[NSYMS] = {}; 26 24 27 25 ELF(Phdr) *pt = (ELF(Phdr) *)(raw_addr + GET_BE(&hdr->e_phoff)); ··· 62 64 } 63 65 64 66 /* Walk the section table */ 65 - secstrings_hdr = raw_addr + GET_BE(&hdr->e_shoff) + 66 - GET_BE(&hdr->e_shentsize)*GET_BE(&hdr->e_shstrndx); 67 - secstrings = raw_addr + GET_BE(&secstrings_hdr->sh_offset); 68 67 for (i = 0; i < GET_BE(&hdr->e_shnum); i++) { 69 68 ELF(Shdr) *sh = raw_addr + GET_BE(&hdr->e_shoff) + 70 69 GET_BE(&hdr->e_shentsize) * i; 71 70 if (GET_BE(&sh->sh_type) == SHT_SYMTAB) 72 71 symtab_hdr = sh; 73 - 74 - if (!strcmp(secstrings + GET_BE(&sh->sh_name), 75 - ".tick_patch")) 76 - patch_sec = sh; 77 72 } 78 73 79 74 if (!symtab_hdr) ··· 133 142 fprintf(outfile, "const struct vdso_image %s_builtin = {\n", name); 134 143 fprintf(outfile, "\t.data = raw_data,\n"); 135 144 fprintf(outfile, "\t.size = %lu,\n", mapping_size); 136 - if (patch_sec) { 137 - fprintf(outfile, "\t.tick_patch = %lu,\n", 138 - (unsigned long)GET_BE(&patch_sec->sh_offset)); 139 - fprintf(outfile, "\t.tick_patch_len = %lu,\n", 140 - (unsigned long)GET_BE(&patch_sec->sh_size)); 141 - } 142 145 for (i = 0; i < NSYMS; i++) { 143 146 if (required_syms[i].export && syms[i]) 144 147 fprintf(outfile, "\t.sym_%s = %" PRIi64 ",\n",
+2
arch/sparc/vdso/vdso32/vdso32.lds.S
··· 17 17 global: 18 18 clock_gettime; 19 19 __vdso_clock_gettime; 20 + __vdso_clock_gettime_stick; 20 21 gettimeofday; 21 22 __vdso_gettimeofday; 23 + __vdso_gettimeofday_stick; 22 24 local: *; 23 25 }; 24 26 }
+203 -23
arch/sparc/vdso/vma.c
··· 42 42 43 43 struct vvar_data *vvar_data; 44 44 45 - struct tick_patch_entry { 46 - s32 orig, repl; 45 + struct vdso_elfinfo32 { 46 + Elf32_Ehdr *hdr; 47 + Elf32_Sym *dynsym; 48 + unsigned long dynsymsize; 49 + const char *dynstr; 50 + unsigned long text; 47 51 }; 48 52 49 - static void stick_patch(const struct vdso_image *image) 53 + struct vdso_elfinfo64 { 54 + Elf64_Ehdr *hdr; 55 + Elf64_Sym *dynsym; 56 + unsigned long dynsymsize; 57 + const char *dynstr; 58 + unsigned long text; 59 + }; 60 + 61 + struct vdso_elfinfo { 62 + union { 63 + struct vdso_elfinfo32 elf32; 64 + struct vdso_elfinfo64 elf64; 65 + } u; 66 + }; 67 + 68 + static void *one_section64(struct vdso_elfinfo64 *e, const char *name, 69 + unsigned long *size) 50 70 { 51 - struct tick_patch_entry *p, *p_end; 71 + const char *snames; 72 + Elf64_Shdr *shdrs; 73 + unsigned int i; 52 74 53 - p = image->data + image->tick_patch; 54 - p_end = (void *)p + image->tick_patch_len; 55 - while (p < p_end) { 56 - u32 *instr = (void *)&p->orig + p->orig; 57 - u32 *repl = (void *)&p->repl + p->repl; 58 - 59 - *instr = *repl; 60 - flushi(instr); 61 - p++; 75 + shdrs = (void *)e->hdr + e->hdr->e_shoff; 76 + snames = (void *)e->hdr + shdrs[e->hdr->e_shstrndx].sh_offset; 77 + for (i = 1; i < e->hdr->e_shnum; i++) { 78 + if (!strcmp(snames+shdrs[i].sh_name, name)) { 79 + if (size) 80 + *size = shdrs[i].sh_size; 81 + return (void *)e->hdr + shdrs[i].sh_offset; 82 + } 62 83 } 84 + return NULL; 85 + } 86 + 87 + static int find_sections64(const struct vdso_image *image, struct vdso_elfinfo *_e) 88 + { 89 + struct vdso_elfinfo64 *e = &_e->u.elf64; 90 + 91 + e->hdr = image->data; 92 + e->dynsym = one_section64(e, ".dynsym", &e->dynsymsize); 93 + e->dynstr = one_section64(e, ".dynstr", NULL); 94 + 95 + if (!e->dynsym || !e->dynstr) { 96 + pr_err("VDSO64: Missing symbol sections.\n"); 97 + return -ENODEV; 98 + } 99 + return 0; 100 + } 101 + 102 + static Elf64_Sym *find_sym64(const struct vdso_elfinfo64 *e, const char *name) 103 + { 104 + unsigned int i; 105 + 106 + for (i = 0; i < (e->dynsymsize / sizeof(Elf64_Sym)); i++) { 107 + Elf64_Sym *s = &e->dynsym[i]; 108 + if (s->st_name == 0) 109 + continue; 110 + if (!strcmp(e->dynstr + s->st_name, name)) 111 + return s; 112 + } 113 + return NULL; 114 + } 115 + 116 + static int patchsym64(struct vdso_elfinfo *_e, const char *orig, 117 + const char *new) 118 + { 119 + struct vdso_elfinfo64 *e = &_e->u.elf64; 120 + Elf64_Sym *osym = find_sym64(e, orig); 121 + Elf64_Sym *nsym = find_sym64(e, new); 122 + 123 + if (!nsym || !osym) { 124 + pr_err("VDSO64: Missing symbols.\n"); 125 + return -ENODEV; 126 + } 127 + osym->st_value = nsym->st_value; 128 + osym->st_size = nsym->st_size; 129 + osym->st_info = nsym->st_info; 130 + osym->st_other = nsym->st_other; 131 + osym->st_shndx = nsym->st_shndx; 132 + 133 + return 0; 134 + } 135 + 136 + static void *one_section32(struct vdso_elfinfo32 *e, const char *name, 137 + unsigned long *size) 138 + { 139 + const char *snames; 140 + Elf32_Shdr *shdrs; 141 + unsigned int i; 142 + 143 + shdrs = (void *)e->hdr + e->hdr->e_shoff; 144 + snames = (void *)e->hdr + shdrs[e->hdr->e_shstrndx].sh_offset; 145 + for (i = 1; i < e->hdr->e_shnum; i++) { 146 + if (!strcmp(snames+shdrs[i].sh_name, name)) { 147 + if (size) 148 + *size = shdrs[i].sh_size; 149 + return (void *)e->hdr + shdrs[i].sh_offset; 150 + } 151 + } 152 + return NULL; 153 + } 154 + 155 + static int find_sections32(const struct vdso_image *image, struct vdso_elfinfo *_e) 156 + { 157 + struct vdso_elfinfo32 *e = &_e->u.elf32; 158 + 159 + e->hdr = image->data; 160 + e->dynsym = one_section32(e, ".dynsym", &e->dynsymsize); 161 + e->dynstr = one_section32(e, ".dynstr", NULL); 162 + 163 + if (!e->dynsym || !e->dynstr) { 164 + pr_err("VDSO32: Missing symbol sections.\n"); 165 + return -ENODEV; 166 + } 167 + return 0; 168 + } 169 + 170 + static Elf32_Sym *find_sym32(const struct vdso_elfinfo32 *e, const char *name) 171 + { 172 + unsigned int i; 173 + 174 + for (i = 0; i < (e->dynsymsize / sizeof(Elf32_Sym)); i++) { 175 + Elf32_Sym *s = &e->dynsym[i]; 176 + if (s->st_name == 0) 177 + continue; 178 + if (!strcmp(e->dynstr + s->st_name, name)) 179 + return s; 180 + } 181 + return NULL; 182 + } 183 + 184 + static int patchsym32(struct vdso_elfinfo *_e, const char *orig, 185 + const char *new) 186 + { 187 + struct vdso_elfinfo32 *e = &_e->u.elf32; 188 + Elf32_Sym *osym = find_sym32(e, orig); 189 + Elf32_Sym *nsym = find_sym32(e, new); 190 + 191 + if (!nsym || !osym) { 192 + pr_err("VDSO32: Missing symbols.\n"); 193 + return -ENODEV; 194 + } 195 + osym->st_value = nsym->st_value; 196 + osym->st_size = nsym->st_size; 197 + osym->st_info = nsym->st_info; 198 + osym->st_other = nsym->st_other; 199 + osym->st_shndx = nsym->st_shndx; 200 + 201 + return 0; 202 + } 203 + 204 + static int find_sections(const struct vdso_image *image, struct vdso_elfinfo *e, 205 + bool elf64) 206 + { 207 + if (elf64) 208 + return find_sections64(image, e); 209 + else 210 + return find_sections32(image, e); 211 + } 212 + 213 + static int patch_one_symbol(struct vdso_elfinfo *e, const char *orig, 214 + const char *new_target, bool elf64) 215 + { 216 + if (elf64) 217 + return patchsym64(e, orig, new_target); 218 + else 219 + return patchsym32(e, orig, new_target); 220 + } 221 + 222 + static int stick_patch(const struct vdso_image *image, struct vdso_elfinfo *e, bool elf64) 223 + { 224 + int err; 225 + 226 + err = find_sections(image, e, elf64); 227 + if (err) 228 + return err; 229 + 230 + err = patch_one_symbol(e, 231 + "__vdso_gettimeofday", 232 + "__vdso_gettimeofday_stick", elf64); 233 + if (err) 234 + return err; 235 + 236 + return patch_one_symbol(e, 237 + "__vdso_clock_gettime", 238 + "__vdso_clock_gettime_stick", elf64); 239 + return 0; 63 240 } 64 241 65 242 /* ··· 244 67 * kernel image. 245 68 */ 246 69 int __init init_vdso_image(const struct vdso_image *image, 247 - struct vm_special_mapping *vdso_mapping) 70 + struct vm_special_mapping *vdso_mapping, bool elf64) 248 71 { 249 - int i; 250 - struct page *dp, **dpp = NULL; 251 - int dnpages = 0; 252 - struct page *cp, **cpp = NULL; 253 72 int cnpages = (image->size) / PAGE_SIZE; 73 + struct page *dp, **dpp = NULL; 74 + struct page *cp, **cpp = NULL; 75 + struct vdso_elfinfo ei; 76 + int i, dnpages = 0; 77 + 78 + if (tlb_type != spitfire) { 79 + int err = stick_patch(image, &ei, elf64); 80 + if (err) 81 + return err; 82 + } 254 83 255 84 /* 256 85 * First, the vdso text. This is initialied data, an integral number of ··· 270 87 271 88 if (!cpp) 272 89 goto oom; 273 - 274 - if (tlb_type != spitfire) 275 - stick_patch(image); 276 90 277 91 for (i = 0; i < cnpages; i++) { 278 92 cp = alloc_page(GFP_KERNEL); ··· 333 153 { 334 154 int err = 0; 335 155 #ifdef CONFIG_SPARC64 336 - err = init_vdso_image(&vdso_image_64_builtin, &vdso_mapping64); 156 + err = init_vdso_image(&vdso_image_64_builtin, &vdso_mapping64, true); 337 157 if (err) 338 158 return err; 339 159 #endif 340 160 341 161 #ifdef CONFIG_COMPAT 342 - err = init_vdso_image(&vdso_image_32_builtin, &vdso_mapping32); 162 + err = init_vdso_image(&vdso_image_32_builtin, &vdso_mapping32, false); 343 163 #endif 344 164 return err; 345 165