]>
git.proxmox.com Git - mirror_ubuntu-eoan-kernel.git/blob - arch/riscv/kernel/module-sections.c
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 unsigned long module_emit_got_entry(struct module
*mod
, unsigned long 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
);
19 return (unsigned long)got
;
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
);
28 return (unsigned long)&got
[i
];
31 unsigned long module_emit_plt_entry(struct module
*mod
, unsigned long 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
;
40 return (unsigned long)plt
;
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
,
47 (unsigned long)&plt
[i
],
48 (unsigned long)&got_plt
[i
]);
50 plt_sec
->num_entries
++;
51 got_plt_sec
->num_entries
++;
52 BUG_ON(plt_sec
->num_entries
> plt_sec
->max_entries
);
54 return (unsigned long)&plt
[i
];
57 static int is_rela_equal(const Elf_Rela
*x
, const Elf_Rela
*y
)
59 return x
->r_info
== y
->r_info
&& x
->r_addend
== y
->r_addend
;
62 static bool duplicate_rela(const Elf_Rela
*rela
, int idx
)
65 for (i
= 0; i
< idx
; i
++) {
66 if (is_rela_equal(&rela
[i
], &rela
[idx
]))
72 static void count_max_entries(Elf_Rela
*relas
, int num
,
73 unsigned int *plts
, unsigned int *gots
)
77 for (i
= 0; i
< num
; i
++) {
78 type
= ELF_RISCV_R_TYPE(relas
[i
].r_info
);
79 if (type
== R_RISCV_CALL_PLT
) {
80 if (!duplicate_rela(relas
, i
))
82 } else if (type
== R_RISCV_GOT_HI20
) {
83 if (!duplicate_rela(relas
, i
))
89 int module_frob_arch_sections(Elf_Ehdr
*ehdr
, Elf_Shdr
*sechdrs
,
90 char *secstrings
, struct module
*mod
)
92 unsigned int num_plts
= 0;
93 unsigned int num_gots
= 0;
97 * Find the empty .got and .plt sections.
99 for (i
= 0; i
< ehdr
->e_shnum
; i
++) {
100 if (!strcmp(secstrings
+ sechdrs
[i
].sh_name
, ".plt"))
101 mod
->arch
.plt
.shdr
= sechdrs
+ i
;
102 else if (!strcmp(secstrings
+ sechdrs
[i
].sh_name
, ".got"))
103 mod
->arch
.got
.shdr
= sechdrs
+ i
;
104 else if (!strcmp(secstrings
+ sechdrs
[i
].sh_name
, ".got.plt"))
105 mod
->arch
.got_plt
.shdr
= sechdrs
+ i
;
108 if (!mod
->arch
.plt
.shdr
) {
109 pr_err("%s: module PLT section(s) missing\n", mod
->name
);
112 if (!mod
->arch
.got
.shdr
) {
113 pr_err("%s: module GOT section(s) missing\n", mod
->name
);
116 if (!mod
->arch
.got_plt
.shdr
) {
117 pr_err("%s: module GOT.PLT section(s) missing\n", mod
->name
);
121 /* Calculate the maxinum number of entries */
122 for (i
= 0; i
< ehdr
->e_shnum
; i
++) {
123 Elf_Rela
*relas
= (void *)ehdr
+ sechdrs
[i
].sh_offset
;
124 int num_rela
= sechdrs
[i
].sh_size
/ sizeof(Elf_Rela
);
125 Elf_Shdr
*dst_sec
= sechdrs
+ sechdrs
[i
].sh_info
;
127 if (sechdrs
[i
].sh_type
!= SHT_RELA
)
130 /* ignore relocations that operate on non-exec sections */
131 if (!(dst_sec
->sh_flags
& SHF_EXECINSTR
))
134 count_max_entries(relas
, num_rela
, &num_plts
, &num_gots
);
137 mod
->arch
.plt
.shdr
->sh_type
= SHT_NOBITS
;
138 mod
->arch
.plt
.shdr
->sh_flags
= SHF_EXECINSTR
| SHF_ALLOC
;
139 mod
->arch
.plt
.shdr
->sh_addralign
= L1_CACHE_BYTES
;
140 mod
->arch
.plt
.shdr
->sh_size
= (num_plts
+ 1) * sizeof(struct plt_entry
);
141 mod
->arch
.plt
.num_entries
= 0;
142 mod
->arch
.plt
.max_entries
= num_plts
;
144 mod
->arch
.got
.shdr
->sh_type
= SHT_NOBITS
;
145 mod
->arch
.got
.shdr
->sh_flags
= SHF_ALLOC
;
146 mod
->arch
.got
.shdr
->sh_addralign
= L1_CACHE_BYTES
;
147 mod
->arch
.got
.shdr
->sh_size
= (num_gots
+ 1) * sizeof(struct got_entry
);
148 mod
->arch
.got
.num_entries
= 0;
149 mod
->arch
.got
.max_entries
= num_gots
;
151 mod
->arch
.got_plt
.shdr
->sh_type
= SHT_NOBITS
;
152 mod
->arch
.got_plt
.shdr
->sh_flags
= SHF_ALLOC
;
153 mod
->arch
.got_plt
.shdr
->sh_addralign
= L1_CACHE_BYTES
;
154 mod
->arch
.got_plt
.shdr
->sh_size
= (num_plts
+ 1) * sizeof(struct got_entry
);
155 mod
->arch
.got_plt
.num_entries
= 0;
156 mod
->arch
.got_plt
.max_entries
= num_plts
;