1 /* SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2014-2017 Linaro Ltd. <ard.biesheuvel@linaro.org>
5 * Copyright (C) 2018 Andes Technology Corporation <zong@andestech.com>
9 #include <linux/kernel.h>
10 #include <linux/module.h>
12 u64
module_emit_got_entry(struct module
*mod
, u64 val
)
14 struct mod_section
*got_sec
= &mod
->arch
.got
;
15 int i
= got_sec
->num_entries
;
16 struct got_entry
*got
= get_got_entry(val
, got_sec
);
21 /* There is no duplicate entry, create a new one */
22 got
= (struct got_entry
*)got_sec
->shdr
->sh_addr
;
23 got
[i
] = emit_got_entry(val
);
25 got_sec
->num_entries
++;
26 BUG_ON(got_sec
->num_entries
> got_sec
->max_entries
);
31 u64
module_emit_plt_entry(struct module
*mod
, u64 val
)
33 struct mod_section
*got_plt_sec
= &mod
->arch
.got_plt
;
34 struct got_entry
*got_plt
;
35 struct mod_section
*plt_sec
= &mod
->arch
.plt
;
36 struct plt_entry
*plt
= get_plt_entry(val
, plt_sec
, got_plt_sec
);
37 int i
= plt_sec
->num_entries
;
42 /* There is no duplicate entry, create a new one */
43 got_plt
= (struct got_entry
*)got_plt_sec
->shdr
->sh_addr
;
44 got_plt
[i
] = emit_got_entry(val
);
45 plt
= (struct plt_entry
*)plt_sec
->shdr
->sh_addr
;
46 plt
[i
] = emit_plt_entry(val
, (u64
)&plt
[i
], (u64
)&got_plt
[i
]);
48 plt_sec
->num_entries
++;
49 got_plt_sec
->num_entries
++;
50 BUG_ON(plt_sec
->num_entries
> plt_sec
->max_entries
);
55 static int is_rela_equal(const Elf64_Rela
*x
, const Elf64_Rela
*y
)
57 return x
->r_info
== y
->r_info
&& x
->r_addend
== y
->r_addend
;
60 static bool duplicate_rela(const Elf64_Rela
*rela
, int idx
)
63 for (i
= 0; i
< idx
; i
++) {
64 if (is_rela_equal(&rela
[i
], &rela
[idx
]))
70 static void count_max_entries(Elf64_Rela
*relas
, int num
,
71 unsigned int *plts
, unsigned int *gots
)
75 for (i
= 0; i
< num
; i
++) {
76 type
= ELF64_R_TYPE(relas
[i
].r_info
);
77 if (type
== R_RISCV_CALL_PLT
) {
78 if (!duplicate_rela(relas
, i
))
80 } else if (type
== R_RISCV_GOT_HI20
) {
81 if (!duplicate_rela(relas
, i
))
87 int module_frob_arch_sections(Elf_Ehdr
*ehdr
, Elf_Shdr
*sechdrs
,
88 char *secstrings
, struct module
*mod
)
90 unsigned int num_plts
= 0;
91 unsigned int num_gots
= 0;
95 * Find the empty .got and .plt sections.
97 for (i
= 0; i
< ehdr
->e_shnum
; i
++) {
98 if (!strcmp(secstrings
+ sechdrs
[i
].sh_name
, ".plt"))
99 mod
->arch
.plt
.shdr
= sechdrs
+ i
;
100 else if (!strcmp(secstrings
+ sechdrs
[i
].sh_name
, ".got"))
101 mod
->arch
.got
.shdr
= sechdrs
+ i
;
102 else if (!strcmp(secstrings
+ sechdrs
[i
].sh_name
, ".got.plt"))
103 mod
->arch
.got_plt
.shdr
= sechdrs
+ i
;
106 if (!mod
->arch
.plt
.shdr
) {
107 pr_err("%s: module PLT section(s) missing\n", mod
->name
);
110 if (!mod
->arch
.got
.shdr
) {
111 pr_err("%s: module GOT section(s) missing\n", mod
->name
);
114 if (!mod
->arch
.got_plt
.shdr
) {
115 pr_err("%s: module GOT.PLT section(s) missing\n", mod
->name
);
119 /* Calculate the maxinum number of entries */
120 for (i
= 0; i
< ehdr
->e_shnum
; i
++) {
121 Elf64_Rela
*relas
= (void *)ehdr
+ sechdrs
[i
].sh_offset
;
122 int num_rela
= sechdrs
[i
].sh_size
/ sizeof(Elf64_Rela
);
123 Elf64_Shdr
*dst_sec
= sechdrs
+ sechdrs
[i
].sh_info
;
125 if (sechdrs
[i
].sh_type
!= SHT_RELA
)
128 /* ignore relocations that operate on non-exec sections */
129 if (!(dst_sec
->sh_flags
& SHF_EXECINSTR
))
132 count_max_entries(relas
, num_rela
, &num_plts
, &num_gots
);
135 mod
->arch
.plt
.shdr
->sh_type
= SHT_NOBITS
;
136 mod
->arch
.plt
.shdr
->sh_flags
= SHF_EXECINSTR
| SHF_ALLOC
;
137 mod
->arch
.plt
.shdr
->sh_addralign
= L1_CACHE_BYTES
;
138 mod
->arch
.plt
.shdr
->sh_size
= (num_plts
+ 1) * sizeof(struct plt_entry
);
139 mod
->arch
.plt
.num_entries
= 0;
140 mod
->arch
.plt
.max_entries
= num_plts
;
142 mod
->arch
.got
.shdr
->sh_type
= SHT_NOBITS
;
143 mod
->arch
.got
.shdr
->sh_flags
= SHF_ALLOC
;
144 mod
->arch
.got
.shdr
->sh_addralign
= L1_CACHE_BYTES
;
145 mod
->arch
.got
.shdr
->sh_size
= (num_gots
+ 1) * sizeof(struct got_entry
);
146 mod
->arch
.got
.num_entries
= 0;
147 mod
->arch
.got
.max_entries
= num_gots
;
149 mod
->arch
.got_plt
.shdr
->sh_type
= SHT_NOBITS
;
150 mod
->arch
.got_plt
.shdr
->sh_flags
= SHF_ALLOC
;
151 mod
->arch
.got_plt
.shdr
->sh_addralign
= L1_CACHE_BYTES
;
152 mod
->arch
.got_plt
.shdr
->sh_size
= (num_plts
+ 1) * sizeof(struct got_entry
);
153 mod
->arch
.got_plt
.num_entries
= 0;
154 mod
->arch
.got_plt
.max_entries
= num_plts
;