Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/objtool/arch/loongarch/special.c
26288 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
#include <string.h>
3
#include <objtool/special.h>
4
#include <objtool/warn.h>
5
6
bool arch_support_alt_relocation(struct special_alt *special_alt,
7
struct instruction *insn,
8
struct reloc *reloc)
9
{
10
return false;
11
}
12
13
struct table_info {
14
struct list_head jump_info;
15
unsigned long insn_offset;
16
unsigned long rodata_offset;
17
};
18
19
static void get_rodata_table_size_by_table_annotate(struct objtool_file *file,
20
struct instruction *insn,
21
unsigned long *table_size)
22
{
23
struct section *rsec;
24
struct reloc *reloc;
25
struct list_head table_list;
26
struct table_info *orig_table;
27
struct table_info *next_table;
28
unsigned long tmp_insn_offset;
29
unsigned long tmp_rodata_offset;
30
bool is_valid_list = false;
31
32
rsec = find_section_by_name(file->elf, ".rela.discard.tablejump_annotate");
33
if (!rsec)
34
return;
35
36
INIT_LIST_HEAD(&table_list);
37
38
for_each_reloc(rsec, reloc) {
39
if (reloc->sym->sec->rodata)
40
continue;
41
42
if (strcmp(insn->sec->name, reloc->sym->sec->name))
43
continue;
44
45
orig_table = malloc(sizeof(struct table_info));
46
if (!orig_table) {
47
WARN("malloc failed");
48
return;
49
}
50
51
orig_table->insn_offset = reloc->sym->offset + reloc_addend(reloc);
52
reloc++;
53
orig_table->rodata_offset = reloc->sym->offset + reloc_addend(reloc);
54
55
list_add_tail(&orig_table->jump_info, &table_list);
56
57
if (reloc_idx(reloc) + 1 == sec_num_entries(rsec))
58
break;
59
60
if (strcmp(insn->sec->name, (reloc + 1)->sym->sec->name)) {
61
list_for_each_entry(orig_table, &table_list, jump_info) {
62
if (orig_table->insn_offset == insn->offset) {
63
is_valid_list = true;
64
break;
65
}
66
}
67
68
if (!is_valid_list) {
69
list_del_init(&table_list);
70
continue;
71
}
72
73
break;
74
}
75
}
76
77
list_for_each_entry(orig_table, &table_list, jump_info) {
78
next_table = list_next_entry(orig_table, jump_info);
79
list_for_each_entry_from(next_table, &table_list, jump_info) {
80
if (next_table->rodata_offset < orig_table->rodata_offset) {
81
tmp_insn_offset = next_table->insn_offset;
82
tmp_rodata_offset = next_table->rodata_offset;
83
next_table->insn_offset = orig_table->insn_offset;
84
next_table->rodata_offset = orig_table->rodata_offset;
85
orig_table->insn_offset = tmp_insn_offset;
86
orig_table->rodata_offset = tmp_rodata_offset;
87
}
88
}
89
}
90
91
list_for_each_entry(orig_table, &table_list, jump_info) {
92
if (insn->offset == orig_table->insn_offset) {
93
next_table = list_next_entry(orig_table, jump_info);
94
if (&next_table->jump_info == &table_list) {
95
*table_size = 0;
96
return;
97
}
98
99
while (next_table->rodata_offset == orig_table->rodata_offset) {
100
next_table = list_next_entry(next_table, jump_info);
101
if (&next_table->jump_info == &table_list) {
102
*table_size = 0;
103
return;
104
}
105
}
106
107
*table_size = next_table->rodata_offset - orig_table->rodata_offset;
108
}
109
}
110
}
111
112
static struct reloc *find_reloc_by_table_annotate(struct objtool_file *file,
113
struct instruction *insn,
114
unsigned long *table_size)
115
{
116
struct section *rsec;
117
struct reloc *reloc;
118
unsigned long offset;
119
120
rsec = find_section_by_name(file->elf, ".rela.discard.tablejump_annotate");
121
if (!rsec)
122
return NULL;
123
124
for_each_reloc(rsec, reloc) {
125
if (reloc->sym->sec->rodata)
126
continue;
127
128
if (strcmp(insn->sec->name, reloc->sym->sec->name))
129
continue;
130
131
offset = reloc->sym->offset + reloc_addend(reloc);
132
if (insn->offset == offset) {
133
get_rodata_table_size_by_table_annotate(file, insn, table_size);
134
reloc++;
135
return reloc;
136
}
137
}
138
139
return NULL;
140
}
141
142
static struct reloc *find_reloc_of_rodata_c_jump_table(struct section *sec,
143
unsigned long offset,
144
unsigned long *table_size)
145
{
146
struct section *rsec;
147
struct reloc *reloc;
148
149
rsec = sec->rsec;
150
if (!rsec)
151
return NULL;
152
153
for_each_reloc(rsec, reloc) {
154
if (reloc_offset(reloc) > offset)
155
break;
156
157
if (!strcmp(reloc->sym->sec->name, C_JUMP_TABLE_SECTION)) {
158
*table_size = 0;
159
return reloc;
160
}
161
}
162
163
return NULL;
164
}
165
166
struct reloc *arch_find_switch_table(struct objtool_file *file,
167
struct instruction *insn,
168
unsigned long *table_size)
169
{
170
struct reloc *annotate_reloc;
171
struct reloc *rodata_reloc;
172
struct section *table_sec;
173
unsigned long table_offset;
174
175
annotate_reloc = find_reloc_by_table_annotate(file, insn, table_size);
176
if (!annotate_reloc) {
177
annotate_reloc = find_reloc_of_rodata_c_jump_table(
178
insn->sec, insn->offset, table_size);
179
if (!annotate_reloc)
180
return NULL;
181
}
182
183
table_sec = annotate_reloc->sym->sec;
184
table_offset = annotate_reloc->sym->offset + reloc_addend(annotate_reloc);
185
186
/*
187
* Each table entry has a rela associated with it. The rela
188
* should reference text in the same function as the original
189
* instruction.
190
*/
191
rodata_reloc = find_reloc_by_dest(file->elf, table_sec, table_offset);
192
if (!rodata_reloc)
193
return NULL;
194
195
return rodata_reloc;
196
}
197
198