Path: blob/master/tools/objtool/arch/loongarch/special.c
26288 views
// SPDX-License-Identifier: GPL-2.0-or-later1#include <string.h>2#include <objtool/special.h>3#include <objtool/warn.h>45bool arch_support_alt_relocation(struct special_alt *special_alt,6struct instruction *insn,7struct reloc *reloc)8{9return false;10}1112struct table_info {13struct list_head jump_info;14unsigned long insn_offset;15unsigned long rodata_offset;16};1718static void get_rodata_table_size_by_table_annotate(struct objtool_file *file,19struct instruction *insn,20unsigned long *table_size)21{22struct section *rsec;23struct reloc *reloc;24struct list_head table_list;25struct table_info *orig_table;26struct table_info *next_table;27unsigned long tmp_insn_offset;28unsigned long tmp_rodata_offset;29bool is_valid_list = false;3031rsec = find_section_by_name(file->elf, ".rela.discard.tablejump_annotate");32if (!rsec)33return;3435INIT_LIST_HEAD(&table_list);3637for_each_reloc(rsec, reloc) {38if (reloc->sym->sec->rodata)39continue;4041if (strcmp(insn->sec->name, reloc->sym->sec->name))42continue;4344orig_table = malloc(sizeof(struct table_info));45if (!orig_table) {46WARN("malloc failed");47return;48}4950orig_table->insn_offset = reloc->sym->offset + reloc_addend(reloc);51reloc++;52orig_table->rodata_offset = reloc->sym->offset + reloc_addend(reloc);5354list_add_tail(&orig_table->jump_info, &table_list);5556if (reloc_idx(reloc) + 1 == sec_num_entries(rsec))57break;5859if (strcmp(insn->sec->name, (reloc + 1)->sym->sec->name)) {60list_for_each_entry(orig_table, &table_list, jump_info) {61if (orig_table->insn_offset == insn->offset) {62is_valid_list = true;63break;64}65}6667if (!is_valid_list) {68list_del_init(&table_list);69continue;70}7172break;73}74}7576list_for_each_entry(orig_table, &table_list, jump_info) {77next_table = list_next_entry(orig_table, jump_info);78list_for_each_entry_from(next_table, &table_list, jump_info) {79if (next_table->rodata_offset < orig_table->rodata_offset) {80tmp_insn_offset = next_table->insn_offset;81tmp_rodata_offset = next_table->rodata_offset;82next_table->insn_offset = orig_table->insn_offset;83next_table->rodata_offset = orig_table->rodata_offset;84orig_table->insn_offset = tmp_insn_offset;85orig_table->rodata_offset = tmp_rodata_offset;86}87}88}8990list_for_each_entry(orig_table, &table_list, jump_info) {91if (insn->offset == orig_table->insn_offset) {92next_table = list_next_entry(orig_table, jump_info);93if (&next_table->jump_info == &table_list) {94*table_size = 0;95return;96}9798while (next_table->rodata_offset == orig_table->rodata_offset) {99next_table = list_next_entry(next_table, jump_info);100if (&next_table->jump_info == &table_list) {101*table_size = 0;102return;103}104}105106*table_size = next_table->rodata_offset - orig_table->rodata_offset;107}108}109}110111static struct reloc *find_reloc_by_table_annotate(struct objtool_file *file,112struct instruction *insn,113unsigned long *table_size)114{115struct section *rsec;116struct reloc *reloc;117unsigned long offset;118119rsec = find_section_by_name(file->elf, ".rela.discard.tablejump_annotate");120if (!rsec)121return NULL;122123for_each_reloc(rsec, reloc) {124if (reloc->sym->sec->rodata)125continue;126127if (strcmp(insn->sec->name, reloc->sym->sec->name))128continue;129130offset = reloc->sym->offset + reloc_addend(reloc);131if (insn->offset == offset) {132get_rodata_table_size_by_table_annotate(file, insn, table_size);133reloc++;134return reloc;135}136}137138return NULL;139}140141static struct reloc *find_reloc_of_rodata_c_jump_table(struct section *sec,142unsigned long offset,143unsigned long *table_size)144{145struct section *rsec;146struct reloc *reloc;147148rsec = sec->rsec;149if (!rsec)150return NULL;151152for_each_reloc(rsec, reloc) {153if (reloc_offset(reloc) > offset)154break;155156if (!strcmp(reloc->sym->sec->name, C_JUMP_TABLE_SECTION)) {157*table_size = 0;158return reloc;159}160}161162return NULL;163}164165struct reloc *arch_find_switch_table(struct objtool_file *file,166struct instruction *insn,167unsigned long *table_size)168{169struct reloc *annotate_reloc;170struct reloc *rodata_reloc;171struct section *table_sec;172unsigned long table_offset;173174annotate_reloc = find_reloc_by_table_annotate(file, insn, table_size);175if (!annotate_reloc) {176annotate_reloc = find_reloc_of_rodata_c_jump_table(177insn->sec, insn->offset, table_size);178if (!annotate_reloc)179return NULL;180}181182table_sec = annotate_reloc->sym->sec;183table_offset = annotate_reloc->sym->offset + reloc_addend(annotate_reloc);184185/*186* Each table entry has a rela associated with it. The rela187* should reference text in the same function as the original188* instruction.189*/190rodata_reloc = find_reloc_by_dest(file->elf, table_sec, table_offset);191if (!rodata_reloc)192return NULL;193194return rodata_reloc;195}196197198