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(x: &rela[i], y: &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(rela: relas, idx: i)) |
82 | (*plts)++; |
83 | } else if (type == R_RISCV_GOT_HI20) { |
84 | if (!duplicate_rela(rela: relas, idx: 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: num_rela, plts: &num_plts, gots: &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 | |