linux/arch/riscv/kernel/module-sections.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0
   2 *
   3 * Copyright (C) 2014-2017 Linaro Ltd. <ard.biesheuvel@linaro.org>
   4 *
   5 * Copyright (C) 2018 Andes Technology Corporation <zong@andestech.com>
   6 */
   7
   8#include <linux/elf.h>
   9#include <linux/kernel.h>
  10#include <linux/module.h>
  11#include <linux/moduleloader.h>
  12
  13unsigned long module_emit_got_entry(struct module *mod, unsigned long val)
  14{
  15        struct mod_section *got_sec = &mod->arch.got;
  16        int i = got_sec->num_entries;
  17        struct got_entry *got = get_got_entry(val, got_sec);
  18
  19        if (got)
  20                return (unsigned long)got;
  21
  22        /* There is no duplicate entry, create a new one */
  23        got = (struct got_entry *)got_sec->shdr->sh_addr;
  24        got[i] = emit_got_entry(val);
  25
  26        got_sec->num_entries++;
  27        BUG_ON(got_sec->num_entries > got_sec->max_entries);
  28
  29        return (unsigned long)&got[i];
  30}
  31
  32unsigned long module_emit_plt_entry(struct module *mod, unsigned long val)
  33{
  34        struct mod_section *got_plt_sec = &mod->arch.got_plt;
  35        struct got_entry *got_plt;
  36        struct mod_section *plt_sec = &mod->arch.plt;
  37        struct plt_entry *plt = get_plt_entry(val, plt_sec, got_plt_sec);
  38        int i = plt_sec->num_entries;
  39
  40        if (plt)
  41                return (unsigned long)plt;
  42
  43        /* There is no duplicate entry, create a new one */
  44        got_plt = (struct got_entry *)got_plt_sec->shdr->sh_addr;
  45        got_plt[i] = emit_got_entry(val);
  46        plt = (struct plt_entry *)plt_sec->shdr->sh_addr;
  47        plt[i] = emit_plt_entry(val,
  48                                (unsigned long)&plt[i],
  49                                (unsigned long)&got_plt[i]);
  50
  51        plt_sec->num_entries++;
  52        got_plt_sec->num_entries++;
  53        BUG_ON(plt_sec->num_entries > plt_sec->max_entries);
  54
  55        return (unsigned long)&plt[i];
  56}
  57
  58static int is_rela_equal(const Elf_Rela *x, const Elf_Rela *y)
  59{
  60        return x->r_info == y->r_info && x->r_addend == y->r_addend;
  61}
  62
  63static bool duplicate_rela(const Elf_Rela *rela, int idx)
  64{
  65        int i;
  66        for (i = 0; i < idx; i++) {
  67                if (is_rela_equal(&rela[i], &rela[idx]))
  68                        return true;
  69        }
  70        return false;
  71}
  72
  73static void count_max_entries(Elf_Rela *relas, int num,
  74                              unsigned int *plts, unsigned int *gots)
  75{
  76        unsigned int type, i;
  77
  78        for (i = 0; i < num; i++) {
  79                type = ELF_RISCV_R_TYPE(relas[i].r_info);
  80                if (type == R_RISCV_CALL_PLT) {
  81                        if (!duplicate_rela(relas, i))
  82                                (*plts)++;
  83                } else if (type == R_RISCV_GOT_HI20) {
  84                        if (!duplicate_rela(relas, i))
  85                                (*gots)++;
  86                }
  87        }
  88}
  89
  90int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
  91                              char *secstrings, struct module *mod)
  92{
  93        unsigned int num_plts = 0;
  94        unsigned int num_gots = 0;
  95        int i;
  96
  97        /*
  98         * Find the empty .got and .plt sections.
  99         */
 100        for (i = 0; i < ehdr->e_shnum; i++) {
 101                if (!strcmp(secstrings + sechdrs[i].sh_name, ".plt"))
 102                        mod->arch.plt.shdr = sechdrs + i;
 103                else if (!strcmp(secstrings + sechdrs[i].sh_name, ".got"))
 104                        mod->arch.got.shdr = sechdrs + i;
 105                else if (!strcmp(secstrings + sechdrs[i].sh_name, ".got.plt"))
 106                        mod->arch.got_plt.shdr = sechdrs + i;
 107        }
 108
 109        if (!mod->arch.plt.shdr) {
 110                pr_err("%s: module PLT section(s) missing\n", mod->name);
 111                return -ENOEXEC;
 112        }
 113        if (!mod->arch.got.shdr) {
 114                pr_err("%s: module GOT section(s) missing\n", mod->name);
 115                return -ENOEXEC;
 116        }
 117        if (!mod->arch.got_plt.shdr) {
 118                pr_err("%s: module GOT.PLT section(s) missing\n", mod->name);
 119                return -ENOEXEC;
 120        }
 121
 122        /* Calculate the maxinum number of entries */
 123        for (i = 0; i < ehdr->e_shnum; i++) {
 124                Elf_Rela *relas = (void *)ehdr + sechdrs[i].sh_offset;
 125                int num_rela = sechdrs[i].sh_size / sizeof(Elf_Rela);
 126                Elf_Shdr *dst_sec = sechdrs + sechdrs[i].sh_info;
 127
 128                if (sechdrs[i].sh_type != SHT_RELA)
 129                        continue;
 130
 131                /* ignore relocations that operate on non-exec sections */
 132                if (!(dst_sec->sh_flags & SHF_EXECINSTR))
 133                        continue;
 134
 135                count_max_entries(relas, num_rela, &num_plts, &num_gots);
 136        }
 137
 138        mod->arch.plt.shdr->sh_type = SHT_NOBITS;
 139        mod->arch.plt.shdr->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
 140        mod->arch.plt.shdr->sh_addralign = L1_CACHE_BYTES;
 141        mod->arch.plt.shdr->sh_size = (num_plts + 1) * sizeof(struct plt_entry);
 142        mod->arch.plt.num_entries = 0;
 143        mod->arch.plt.max_entries = num_plts;
 144
 145        mod->arch.got.shdr->sh_type = SHT_NOBITS;
 146        mod->arch.got.shdr->sh_flags = SHF_ALLOC;
 147        mod->arch.got.shdr->sh_addralign = L1_CACHE_BYTES;
 148        mod->arch.got.shdr->sh_size = (num_gots + 1) * sizeof(struct got_entry);
 149        mod->arch.got.num_entries = 0;
 150        mod->arch.got.max_entries = num_gots;
 151
 152        mod->arch.got_plt.shdr->sh_type = SHT_NOBITS;
 153        mod->arch.got_plt.shdr->sh_flags = SHF_ALLOC;
 154        mod->arch.got_plt.shdr->sh_addralign = L1_CACHE_BYTES;
 155        mod->arch.got_plt.shdr->sh_size = (num_plts + 1) * sizeof(struct got_entry);
 156        mod->arch.got_plt.num_entries = 0;
 157        mod->arch.got_plt.max_entries = num_plts;
 158        return 0;
 159}
 160