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 13 unsigned 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 32 unsigned 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 58 static 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 63 static 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 73 static 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 90 int 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
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.