LCOV - code coverage report
Current view: top level - arch/arm/kernel - module-plts.c (source / functions) Hit Total Coverage
Test: gcov_data_raspi2_real_modules_combined.info Lines: 76 83 91.6 %
Date: 2020-09-30 20:25:40 Functions: 6 6 100.0 %
Branches: 59 69 85.5 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-only
       2                 :            : /*
       3                 :            :  * Copyright (C) 2014-2017 Linaro Ltd. <ard.biesheuvel@linaro.org>
       4                 :            :  */
       5                 :            : 
       6                 :            : #include <linux/elf.h>
       7                 :            : #include <linux/kernel.h>
       8                 :            : #include <linux/module.h>
       9                 :            : #include <linux/sort.h>
      10                 :            : 
      11                 :            : #include <asm/cache.h>
      12                 :            : #include <asm/opcodes.h>
      13                 :            : 
      14                 :            : #define PLT_ENT_STRIDE          L1_CACHE_BYTES
      15                 :            : #define PLT_ENT_COUNT           (PLT_ENT_STRIDE / sizeof(u32))
      16                 :            : #define PLT_ENT_SIZE            (sizeof(struct plt_entries) / PLT_ENT_COUNT)
      17                 :            : 
      18                 :            : #ifdef CONFIG_THUMB2_KERNEL
      19                 :            : #define PLT_ENT_LDR             __opcode_to_mem_thumb32(0xf8dff000 | \
      20                 :            :                                                         (PLT_ENT_STRIDE - 4))
      21                 :            : #else
      22                 :            : #define PLT_ENT_LDR             __opcode_to_mem_arm(0xe59ff000 | \
      23                 :            :                                                     (PLT_ENT_STRIDE - 8))
      24                 :            : #endif
      25                 :            : 
      26                 :            : struct plt_entries {
      27                 :            :         u32     ldr[PLT_ENT_COUNT];
      28                 :            :         u32     lit[PLT_ENT_COUNT];
      29                 :            : };
      30                 :            : 
      31                 :            : static bool in_init(const struct module *mod, unsigned long loc)
      32                 :            : {
      33                 :     667212 :         return loc - (u32)mod->init_layout.base < mod->init_layout.size;
      34                 :            : }
      35                 :            : 
      36                 :     667212 : u32 get_module_plt(struct module *mod, unsigned long loc, Elf32_Addr val)
      37                 :            : {
      38         [ +  + ]:     667212 :         struct mod_plt_sec *pltsec = !in_init(mod, loc) ? &mod->arch.core :
      39                 :            :                                                           &mod->arch.init;
      40                 :            : 
      41                 :     667212 :         struct plt_entries *plt = (struct plt_entries *)pltsec->plt->sh_addr;
      42                 :            :         int idx = 0;
      43                 :            : 
      44                 :            :         /*
      45                 :            :          * Look for an existing entry pointing to 'val'. Given that the
      46                 :            :          * relocations are sorted, this will be the last entry we allocated.
      47                 :            :          * (if one exists).
      48                 :            :          */
      49         [ +  + ]:     667212 :         if (pltsec->plt_count > 0) {
      50                 :     660016 :                 plt += (pltsec->plt_count - 1) / PLT_ENT_COUNT;
      51                 :     660016 :                 idx = (pltsec->plt_count - 1) % PLT_ENT_COUNT;
      52                 :            : 
      53         [ +  + ]:     660016 :                 if (plt->lit[idx] == val)
      54                 :     533530 :                         return (u32)&plt->ldr[idx];
      55                 :            : 
      56                 :     126486 :                 idx = (idx + 1) % PLT_ENT_COUNT;
      57         [ +  + ]:     126486 :                 if (!idx)
      58                 :       5496 :                         plt++;
      59                 :            :         }
      60                 :            : 
      61                 :     133682 :         pltsec->plt_count++;
      62         [ -  + ]:     133682 :         BUG_ON(pltsec->plt_count * PLT_ENT_SIZE > pltsec->plt->sh_size);
      63                 :            : 
      64         [ +  + ]:     133682 :         if (!idx)
      65                 :            :                 /* Populate a new set of entries */
      66                 :      12692 :                 *plt = (struct plt_entries){
      67                 :            :                         { [0 ... PLT_ENT_COUNT - 1] = PLT_ENT_LDR, },
      68                 :            :                         { val, }
      69                 :            :                 };
      70                 :            :         else
      71                 :     120990 :                 plt->lit[idx] = val;
      72                 :            : 
      73                 :     133682 :         return (u32)&plt->ldr[idx];
      74                 :            : }
      75                 :            : 
      76                 :            : #define cmp_3way(a,b)   ((a) < (b) ? -1 : (a) > (b))
      77                 :            : 
      78                 :  185547327 : static int cmp_rel(const void *a, const void *b)
      79                 :            : {
      80                 :            :         const Elf32_Rel *x = a, *y = b;
      81                 :            :         int i;
      82                 :            : 
      83                 :            :         /* sort by type and symbol index */
      84   [ +  -  +  + ]:  190612974 :         i = cmp_3way(ELF32_R_TYPE(x->r_info), ELF32_R_TYPE(y->r_info));
      85   [ +  +  +  + ]:  190612974 :         if (i == 0)
      86   [ +  +  +  + ]:  155915418 :                 i = cmp_3way(ELF32_R_SYM(x->r_info), ELF32_R_SYM(y->r_info));
      87                 :  185547327 :         return i;
      88                 :            : }
      89                 :            : 
      90                 :    9386775 : static bool is_zero_addend_relocation(Elf32_Addr base, const Elf32_Rel *rel)
      91                 :            : {
      92                 :    9386775 :         u32 *tval = (u32 *)(base + rel->r_offset);
      93                 :            : 
      94                 :            :         /*
      95                 :            :          * Do a bitwise compare on the raw addend rather than fully decoding
      96                 :            :          * the offset and doing an arithmetic comparison.
      97                 :            :          * Note that a zero-addend jump/call relocation is encoded taking the
      98                 :            :          * PC bias into account, i.e., -8 for ARM and -4 for Thumb2.
      99                 :            :          */
     100      [ -  +  - ]:    9386775 :         switch (ELF32_R_TYPE(rel->r_info)) {
     101                 :            :                 u16 upper, lower;
     102                 :            : 
     103                 :            :         case R_ARM_THM_CALL:
     104                 :            :         case R_ARM_THM_JUMP24:
     105                 :          0 :                 upper = __mem_to_opcode_thumb16(((u16 *)tval)[0]);
     106                 :          0 :                 lower = __mem_to_opcode_thumb16(((u16 *)tval)[1]);
     107                 :            : 
     108   [ #  #  #  # ]:          0 :                 return (upper & 0x7ff) == 0x7ff && (lower & 0x2fff) == 0x2ffe;
     109                 :            : 
     110                 :            :         case R_ARM_CALL:
     111                 :            :         case R_ARM_PC24:
     112                 :            :         case R_ARM_JUMP24:
     113                 :    9386775 :                 return (__mem_to_opcode_arm(*tval) & 0xffffff) == 0xfffffe;
     114                 :            :         }
     115                 :          0 :         BUG();
     116                 :            : }
     117                 :            : 
     118                 :    5080660 : static bool duplicate_rel(Elf32_Addr base, const Elf32_Rel *rel, int num)
     119                 :            : {
     120                 :            :         const Elf32_Rel *prev;
     121                 :            : 
     122                 :            :         /*
     123                 :            :          * Entries are sorted by type and symbol index. That means that,
     124                 :            :          * if a duplicate entry exists, it must be in the preceding
     125                 :            :          * slot.
     126                 :            :          */
     127         [ +  + ]:    5080660 :         if (!num)
     128                 :            :                 return false;
     129                 :            : 
     130                 :    5065647 :         prev = rel + num - 1;
     131   [ +  +  -  + ]:   14453102 :         return cmp_rel(rel + num, prev) == 0 &&
     132                 :    4333515 :                is_zero_addend_relocation(base, prev);
     133                 :            : }
     134                 :            : 
     135                 :            : /* Count how many PLT entries we may need */
     136                 :      44787 : static unsigned int count_plts(const Elf32_Sym *syms, Elf32_Addr base,
     137                 :            :                                const Elf32_Rel *rel, int num, Elf32_Word dstidx)
     138                 :            : {
     139                 :            :         unsigned int ret = 0;
     140                 :            :         const Elf32_Sym *s;
     141                 :            :         int i;
     142                 :            : 
     143         [ +  + ]:   14516454 :         for (i = 0; i < num; i++) {
     144         [ +  + ]:   14473654 :                 switch (ELF32_R_TYPE(rel[i].r_info)) {
     145                 :            :                 case R_ARM_CALL:
     146                 :            :                 case R_ARM_PC24:
     147                 :            :                 case R_ARM_JUMP24:
     148                 :            :                 case R_ARM_THM_CALL:
     149                 :            :                 case R_ARM_THM_JUMP24:
     150                 :            :                         /*
     151                 :            :                          * We only have to consider branch targets that resolve
     152                 :            :                          * to symbols that are defined in a different section.
     153                 :            :                          * This is not simply a heuristic, it is a fundamental
     154                 :            :                          * limitation, since there is no guaranteed way to emit
     155                 :            :                          * PLT entries sufficiently close to the branch if the
     156                 :            :                          * section size exceeds the range of a branch
     157                 :            :                          * instruction. So ignore relocations against defined
     158                 :            :                          * symbols if they live in the same section as the
     159                 :            :                          * relocation target.
     160                 :            :                          */
     161                 :    5600594 :                         s = syms + ELF32_R_SYM(rel[i].r_info);
     162         [ +  + ]:    5600594 :                         if (s->st_shndx == dstidx)
     163                 :            :                                 break;
     164                 :            : 
     165                 :            :                         /*
     166                 :            :                          * Jump relocations with non-zero addends against
     167                 :            :                          * undefined symbols are supported by the ELF spec, but
     168                 :            :                          * do not occur in practice (e.g., 'jump n bytes past
     169                 :            :                          * the entry point of undefined function symbol f').
     170                 :            :                          * So we need to support them, but there is no need to
     171                 :            :                          * take them into consideration when trying to optimize
     172                 :            :                          * this code. So let's only check for duplicates when
     173                 :            :                          * the addend is zero. (Note that calls into the core
     174                 :            :                          * module via init PLT entries could involve section
     175                 :            :                          * relative symbol references with non-zero addends, for
     176                 :            :                          * which we may end up emitting duplicates, but the init
     177                 :            :                          * PLT is released along with the rest of the .init
     178                 :            :                          * region as soon as module loading completes.)
     179                 :            :                          */
     180   [ +  +  +  + ]:   10167741 :                         if (!is_zero_addend_relocation(base, rel + i) ||
     181                 :    5071366 :                             !duplicate_rel(base, rel, i))
     182                 :     754946 :                                 ret++;
     183                 :            :                 }
     184                 :            :         }
     185                 :      42800 :         return ret;
     186                 :            : }
     187                 :            : 
     188                 :      11895 : int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
     189                 :            :                               char *secstrings, struct module *mod)
     190                 :            : {
     191                 :            :         unsigned long core_plts = 0;
     192                 :            :         unsigned long init_plts = 0;
     193                 :      11895 :         Elf32_Shdr *s, *sechdrs_end = sechdrs + ehdr->e_shnum;
     194                 :            :         Elf32_Sym *syms = NULL;
     195                 :            : 
     196                 :            :         /*
     197                 :            :          * To store the PLTs, we expand the .text section for core module code
     198                 :            :          * and for initialization code.
     199                 :            :          */
     200         [ +  + ]:     513489 :         for (s = sechdrs; s < sechdrs_end; ++s) {
     201         [ +  + ]:     501594 :                 if (strcmp(".plt", secstrings + s->sh_name) == 0)
     202                 :      12187 :                         mod->arch.core.plt = s;
     203         [ +  + ]:     489407 :                 else if (strcmp(".init.plt", secstrings + s->sh_name) == 0)
     204                 :      11888 :                         mod->arch.init.plt = s;
     205         [ +  + ]:     477519 :                 else if (s->sh_type == SHT_SYMTAB)
     206                 :      11890 :                         syms = (Elf32_Sym *)s->sh_addr;
     207                 :            :         }
     208                 :            : 
     209   [ +  +  +  + ]:      11895 :         if (!mod->arch.core.plt || !mod->arch.init.plt) {
     210                 :        440 :                 pr_err("%s: module PLT section(s) missing\n", mod->name);
     211                 :          0 :                 return -ENOEXEC;
     212                 :            :         }
     213         [ -  + ]:      12046 :         if (!syms) {
     214                 :          0 :                 pr_err("%s: module symtab section missing\n", mod->name);
     215                 :          0 :                 return -ENOEXEC;
     216                 :            :         }
     217                 :            : 
     218         [ +  + ]:     503016 :         for (s = sechdrs + 1; s < sechdrs_end; ++s) {
     219                 :     491126 :                 Elf32_Rel *rels = (void *)ehdr + s->sh_offset;
     220                 :     491126 :                 int numrels = s->sh_size / sizeof(Elf32_Rel);
     221                 :     491126 :                 Elf32_Shdr *dstsec = sechdrs + s->sh_info;
     222                 :            : 
     223         [ +  + ]:     491126 :                 if (s->sh_type != SHT_REL)
     224                 :     339480 :                         continue;
     225                 :            : 
     226                 :            :                 /* ignore relocations that operate on non-exec sections */
     227         [ +  + ]:     151646 :                 if (!(dstsec->sh_flags & SHF_EXECINSTR))
     228                 :     108665 :                         continue;
     229                 :            : 
     230                 :            :                 /* sort by type and symbol index */
     231                 :      42981 :                 sort(rels, numrels, sizeof(Elf32_Rel), cmp_rel, NULL);
     232                 :            : 
     233         [ +  + ]:      42834 :                 if (strncmp(secstrings + dstsec->sh_name, ".init", 5) != 0)
     234                 :      34091 :                         core_plts += count_plts(syms, dstsec->sh_addr, rels,
     235                 :            :                                                 numrels, s->sh_info);
     236                 :            :                 else
     237                 :       8743 :                         init_plts += count_plts(syms, dstsec->sh_addr, rels,
     238                 :            :                                                 numrels, s->sh_info);
     239                 :            :         }
     240                 :            : 
     241                 :      11890 :         mod->arch.core.plt->sh_type = SHT_NOBITS;
     242                 :      11890 :         mod->arch.core.plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
     243                 :      11890 :         mod->arch.core.plt->sh_addralign = L1_CACHE_BYTES;
     244                 :      11890 :         mod->arch.core.plt->sh_size = round_up(core_plts * PLT_ENT_SIZE,
     245                 :            :                                                sizeof(struct plt_entries));
     246                 :      11890 :         mod->arch.core.plt_count = 0;
     247                 :            : 
     248                 :      11890 :         mod->arch.init.plt->sh_type = SHT_NOBITS;
     249                 :      11890 :         mod->arch.init.plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
     250                 :      11890 :         mod->arch.init.plt->sh_addralign = L1_CACHE_BYTES;
     251                 :      11890 :         mod->arch.init.plt->sh_size = round_up(init_plts * PLT_ENT_SIZE,
     252                 :            :                                                sizeof(struct plt_entries));
     253                 :      11890 :         mod->arch.init.plt_count = 0;
     254                 :            : 
     255                 :            :         pr_debug("%s: plt=%x, init.plt=%x\n", __func__,
     256                 :            :                  mod->arch.core.plt->sh_size, mod->arch.init.plt->sh_size);
     257                 :      11890 :         return 0;
     258                 :            : }

Generated by: LCOV version 1.14