Skip to content

Commit cb8dc63

Browse files
samitolvanenvbajs
authored andcommitted
BACKPORT: recordmcount: support >64k sections
When compiling a kernel with Clang and LTO, we need to run recordmcount on vmlinux.o with a large number of sections, which currently fails as the program doesn't understand extended section indexes. This change adds support for processing binaries with >64k sections. Link: https://lkml.kernel.org/r/20200424193046.160744-1-samitolvanen@google.com Link: https://lore.kernel.org/lkml/CAK7LNARbZhoaA=Nnuw0=gBrkuKbr_4Ng_Ei57uafujZf7Xazgw@mail.gmail.com/ Bug: 166522612 Cc: Kees Cook <keescook@chromium.org> Reviewed-by: Matt Helsley <mhelsley@vmware.com> Signed-off-by: Sami Tolvanen <samitolvanen@google.com> Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org> (cherry picked from commit 4ef57b21d6fb49d2b25c47e4cff467a0c2c8b6b7) Signed-off-by: Sami Tolvanen <samitolvanen@google.com> Change-Id: I39acdf51ca882020bbacd5c54299d2e2e6f02ed3 Signed-off-by: atndko <z1281552865@gmail.com> Signed-off-by: Yahya Wessam <yahyawessam2002@gmail.com>
1 parent f621059 commit cb8dc63

File tree

1 file changed

+92
-6
lines changed

1 file changed

+92
-6
lines changed

scripts/recordmcount.h

Lines changed: 92 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@
3030
#undef has_rel_mcount
3131
#undef tot_relsize
3232
#undef get_mcountsym
33+
#undef find_symtab
34+
#undef get_shnum
35+
#undef set_shnum
36+
#undef get_shstrndx
37+
#undef get_symindex
3338
#undef get_sym_str_and_relp
3439
#undef do_func
3540
#undef Elf_Addr
@@ -59,6 +64,11 @@
5964
# define __has_rel_mcount __has64_rel_mcount
6065
# define has_rel_mcount has64_rel_mcount
6166
# define tot_relsize tot64_relsize
67+
# define find_symtab find_symtab64
68+
# define get_shnum get_shnum64
69+
# define set_shnum set_shnum64
70+
# define get_shstrndx get_shstrndx64
71+
# define get_symindex get_symindex64
6272
# define get_sym_str_and_relp get_sym_str_and_relp_64
6373
# define do_func do64
6474
# define get_mcountsym get_mcountsym_64
@@ -92,6 +102,11 @@
92102
# define __has_rel_mcount __has32_rel_mcount
93103
# define has_rel_mcount has32_rel_mcount
94104
# define tot_relsize tot32_relsize
105+
# define find_symtab find_symtab32
106+
# define get_shnum get_shnum32
107+
# define set_shnum set_shnum32
108+
# define get_shstrndx get_shstrndx32
109+
# define get_symindex get_symindex32
95110
# define get_sym_str_and_relp get_sym_str_and_relp_32
96111
# define do_func do32
97112
# define get_mcountsym get_mcountsym_32
@@ -174,6 +189,67 @@ static int MIPS_is_fake_mcount(Elf_Rel const *rp)
174189
return is_fake;
175190
}
176191

192+
static unsigned int get_symindex(Elf_Sym const *sym, Elf32_Word const *symtab,
193+
Elf32_Word const *symtab_shndx)
194+
{
195+
unsigned long offset;
196+
int index;
197+
198+
if (sym->st_shndx != SHN_XINDEX)
199+
return w2(sym->st_shndx);
200+
201+
offset = (unsigned long)sym - (unsigned long)symtab;
202+
index = offset / sizeof(*sym);
203+
204+
return w(symtab_shndx[index]);
205+
}
206+
207+
static unsigned int get_shnum(Elf_Ehdr const *ehdr, Elf_Shdr const *shdr0)
208+
{
209+
if (shdr0 && !ehdr->e_shnum)
210+
return w(shdr0->sh_size);
211+
212+
return w2(ehdr->e_shnum);
213+
}
214+
215+
static void set_shnum(Elf_Ehdr *ehdr, Elf_Shdr *shdr0, unsigned int new_shnum)
216+
{
217+
if (new_shnum >= SHN_LORESERVE) {
218+
ehdr->e_shnum = 0;
219+
shdr0->sh_size = w(new_shnum);
220+
} else
221+
ehdr->e_shnum = w2(new_shnum);
222+
}
223+
224+
static int get_shstrndx(Elf_Ehdr const *ehdr, Elf_Shdr const *shdr0)
225+
{
226+
if (ehdr->e_shstrndx != SHN_XINDEX)
227+
return w2(ehdr->e_shstrndx);
228+
229+
return w(shdr0->sh_link);
230+
}
231+
232+
static void find_symtab(Elf_Ehdr *const ehdr, Elf_Shdr const *shdr0,
233+
unsigned const nhdr, Elf32_Word **symtab,
234+
Elf32_Word **symtab_shndx)
235+
{
236+
Elf_Shdr const *relhdr;
237+
unsigned k;
238+
239+
*symtab = NULL;
240+
*symtab_shndx = NULL;
241+
242+
for (relhdr = shdr0, k = nhdr; k; --k, ++relhdr) {
243+
if (relhdr->sh_type == SHT_SYMTAB)
244+
*symtab = (void *)ehdr + relhdr->sh_offset;
245+
else if (relhdr->sh_type == SHT_SYMTAB_SHNDX)
246+
*symtab_shndx = (void *)ehdr + relhdr->sh_offset;
247+
248+
if (*symtab && *symtab_shndx)
249+
break;
250+
}
251+
}
252+
177253
/* Append the new shstrtab, Elf_Shdr[], __mcount_loc and its relocations. */
178254
static void append_func(Elf_Ehdr *const ehdr,
179255
Elf_Shdr *const shstr,
@@ -189,10 +265,12 @@ static void append_func(Elf_Ehdr *const ehdr,
189265
char const *mc_name = (sizeof(Elf_Rela) == rel_entsize)
190266
? ".rela__mcount_loc"
191267
: ".rel__mcount_loc";
192-
unsigned const old_shnum = w2(ehdr->e_shnum);
193268
uint_t const old_shoff = _w(ehdr->e_shoff);
194269
uint_t const old_shstr_sh_size = _w(shstr->sh_size);
195270
uint_t const old_shstr_sh_offset = _w(shstr->sh_offset);
271+
Elf_Shdr *const shdr0 = (Elf_Shdr *)(old_shoff + (void *)ehdr);
272+
unsigned int const old_shnum = get_shnum(ehdr, shdr0);
273+
unsigned int const new_shnum = 2 + old_shnum; /* {.rel,}__mcount_loc */
196274
uint_t t = 1 + strlen(mc_name) + _w(shstr->sh_size);
197275
uint_t new_e_shoff;
198276

@@ -202,6 +280,8 @@ static void append_func(Elf_Ehdr *const ehdr,
202280
t += (_align & -t); /* word-byte align */
203281
new_e_shoff = t;
204282

283+
set_shnum(ehdr, shdr0, new_shnum);
284+
205285
/* body for new shstrtab */
206286
ulseek(fd_map, sb.st_size, SEEK_SET);
207287
uwrite(fd_map, old_shstr_sh_offset + (void *)ehdr, old_shstr_sh_size);
@@ -246,7 +326,6 @@ static void append_func(Elf_Ehdr *const ehdr,
246326
uwrite(fd_map, mrel0, (void *)mrelp - (void *)mrel0);
247327

248328
ehdr->e_shoff = _w(new_e_shoff);
249-
ehdr->e_shnum = w2(2 + w2(ehdr->e_shnum)); /* {.rel,}__mcount_loc */
250329
ulseek(fd_map, 0, SEEK_SET);
251330
uwrite(fd_map, ehdr, sizeof(*ehdr));
252331
}
@@ -419,6 +498,8 @@ static unsigned find_secsym_ndx(unsigned const txtndx,
419498
char const *const txtname,
420499
uint_t *const recvalp,
421500
Elf_Shdr const *const symhdr,
501+
Elf32_Word const *symtab,
502+
Elf32_Word const *symtab_shndx,
422503
Elf_Ehdr const *const ehdr)
423504
{
424505
Elf_Sym const *const sym0 = (Elf_Sym const *)(_w(symhdr->sh_offset)
@@ -430,7 +511,7 @@ static unsigned find_secsym_ndx(unsigned const txtndx,
430511
for (symp = sym0, t = nsym; t; --t, ++symp) {
431512
unsigned int const st_bind = ELF_ST_BIND(symp->st_info);
432513

433-
if (txtndx == w2(symp->st_shndx)
514+
if (txtndx == get_symindex(symp, symtab, symtab_shndx)
434515
/* avoid STB_WEAK */
435516
&& (STB_LOCAL == st_bind || STB_GLOBAL == st_bind)) {
436517
/* function symbols on ARM have quirks, avoid them */
@@ -498,21 +579,23 @@ static unsigned tot_relsize(Elf_Shdr const *const shdr0,
498579
return totrelsz;
499580
}
500581

501-
502582
/* Overall supervision for Elf32 ET_REL file. */
503583
static void
504584
do_func(Elf_Ehdr *const ehdr, char const *const fname, unsigned const reltype)
505585
{
506586
Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff)
507587
+ (void *)ehdr);
508-
unsigned const nhdr = w2(ehdr->e_shnum);
509-
Elf_Shdr *const shstr = &shdr0[w2(ehdr->e_shstrndx)];
588+
unsigned const nhdr = get_shnum(ehdr, shdr0);
589+
Elf_Shdr *const shstr = &shdr0[get_shstrndx(ehdr, shdr0)];
510590
char const *const shstrtab = (char const *)(_w(shstr->sh_offset)
511591
+ (void *)ehdr);
512592

513593
Elf_Shdr const *relhdr;
514594
unsigned k;
515595

596+
Elf32_Word *symtab;
597+
Elf32_Word *symtab_shndx;
598+
516599
/* Upper bound on space: assume all relevant relocs are for mcount. */
517600
unsigned const totrelsz = tot_relsize(shdr0, nhdr, shstrtab, fname);
518601
Elf_Rel *const mrel0 = umalloc(totrelsz);
@@ -525,6 +608,8 @@ do_func(Elf_Ehdr *const ehdr, char const *const fname, unsigned const reltype)
525608
unsigned rel_entsize = 0;
526609
unsigned symsec_sh_link = 0;
527610

611+
find_symtab(ehdr, shdr0, nhdr, &symtab, &symtab_shndx);
612+
528613
for (relhdr = shdr0, k = nhdr; k; --k, ++relhdr) {
529614
char const *const txtname = has_rel_mcount(relhdr, shdr0,
530615
shstrtab, fname);
@@ -533,6 +618,7 @@ do_func(Elf_Ehdr *const ehdr, char const *const fname, unsigned const reltype)
533618
unsigned const recsym = find_secsym_ndx(
534619
w(relhdr->sh_info), txtname, &recval,
535620
&shdr0[symsec_sh_link = w(relhdr->sh_link)],
621+
symtab, symtab_shndx,
536622
ehdr);
537623

538624
rel_entsize = _w(relhdr->sh_entsize);

0 commit comments

Comments
 (0)