summaryrefslogtreecommitdiff
path: root/tools/objtool/check.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/objtool/check.c')
-rw-r--r--tools/objtool/check.c54
1 files changed, 43 insertions, 11 deletions
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index e128d1c71c30..5422543faff8 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -28,6 +28,8 @@
#include <linux/hashtable.h>
#include <linux/kernel.h>
+#define FAKE_JUMP_OFFSET -1
+
struct alternative {
struct list_head list;
struct instruction *insn;
@@ -163,6 +165,8 @@ static int __dead_end_function(struct objtool_file *file, struct symbol *func,
"__reiserfs_panic",
"lbug_with_loc",
"fortify_panic",
+ "machine_real_restart",
+ "rewind_stack_do_exit",
};
if (func->bind == STB_WEAK)
@@ -498,7 +502,7 @@ static int add_jump_destinations(struct objtool_file *file)
insn->type != INSN_JUMP_UNCONDITIONAL)
continue;
- if (insn->ignore)
+ if (insn->ignore || insn->offset == FAKE_JUMP_OFFSET)
continue;
rela = find_rela_by_dest_range(insn->sec, insn->offset,
@@ -645,10 +649,10 @@ static int handle_group_alt(struct objtool_file *file,
clear_insn_state(&fake_jump->state);
fake_jump->sec = special_alt->new_sec;
- fake_jump->offset = -1;
+ fake_jump->offset = FAKE_JUMP_OFFSET;
fake_jump->type = INSN_JUMP_UNCONDITIONAL;
fake_jump->jump_dest = list_next_entry(last_orig_insn, list);
- fake_jump->ignore = true;
+ fake_jump->func = orig_insn->func;
}
if (!special_alt->new_len) {
@@ -812,7 +816,7 @@ static int add_switch_table(struct objtool_file *file, struct instruction *insn,
struct symbol *pfunc = insn->func->pfunc;
unsigned int prev_offset = 0;
- list_for_each_entry_from(rela, &file->rodata->rela->rela_list, list) {
+ list_for_each_entry_from(rela, &table->rela_sec->rela_list, list) {
if (rela == next_table)
break;
@@ -902,6 +906,7 @@ static struct rela *find_switch_table(struct objtool_file *file,
{
struct rela *text_rela, *rodata_rela;
struct instruction *orig_insn = insn;
+ struct section *rodata_sec;
unsigned long table_offset;
/*
@@ -929,10 +934,13 @@ static struct rela *find_switch_table(struct objtool_file *file,
/* look for a relocation which references .rodata */
text_rela = find_rela_by_dest_range(insn->sec, insn->offset,
insn->len);
- if (!text_rela || text_rela->sym != file->rodata->sym)
+ if (!text_rela || text_rela->sym->type != STT_SECTION ||
+ !text_rela->sym->sec->rodata)
continue;
table_offset = text_rela->addend;
+ rodata_sec = text_rela->sym->sec;
+
if (text_rela->type == R_X86_64_PC32)
table_offset += 4;
@@ -940,10 +948,10 @@ static struct rela *find_switch_table(struct objtool_file *file,
* Make sure the .rodata address isn't associated with a
* symbol. gcc jump tables are anonymous data.
*/
- if (find_symbol_containing(file->rodata, table_offset))
+ if (find_symbol_containing(rodata_sec, table_offset))
continue;
- rodata_rela = find_rela_by_dest(file->rodata, table_offset);
+ rodata_rela = find_rela_by_dest(rodata_sec, table_offset);
if (rodata_rela) {
/*
* Use of RIP-relative switch jumps is quite rare, and
@@ -1028,7 +1036,7 @@ static int add_switch_table_alts(struct objtool_file *file)
struct symbol *func;
int ret;
- if (!file->rodata || !file->rodata->rela)
+ if (!file->rodata)
return 0;
for_each_sec(file, sec) {
@@ -1173,10 +1181,33 @@ static int read_retpoline_hints(struct objtool_file *file)
return 0;
}
+static void mark_rodata(struct objtool_file *file)
+{
+ struct section *sec;
+ bool found = false;
+
+ /*
+ * This searches for the .rodata section or multiple .rodata.func_name
+ * sections if -fdata-sections is being used. The .str.1.1 and .str.1.8
+ * rodata sections are ignored as they don't contain jump tables.
+ */
+ for_each_sec(file, sec) {
+ if (!strncmp(sec->name, ".rodata", 7) &&
+ !strstr(sec->name, ".str1.")) {
+ sec->rodata = true;
+ found = true;
+ }
+ }
+
+ file->rodata = found;
+}
+
static int decode_sections(struct objtool_file *file)
{
int ret;
+ mark_rodata(file);
+
ret = decode_instructions(file);
if (ret)
return ret;
@@ -1779,7 +1810,8 @@ static int validate_branch(struct objtool_file *file, struct instruction *first,
return 1;
}
- func = insn->func ? insn->func->pfunc : NULL;
+ if (insn->func)
+ func = insn->func->pfunc;
if (func && insn->ignore) {
WARN_FUNC("BUG: why am I validating an ignored function?",
@@ -2132,9 +2164,10 @@ static void cleanup(struct objtool_file *file)
elf_close(file->elf);
}
+static struct objtool_file file;
+
int check(const char *_objname, bool orc)
{
- struct objtool_file file;
int ret, warnings = 0;
objname = _objname;
@@ -2146,7 +2179,6 @@ int check(const char *_objname, bool orc)
INIT_LIST_HEAD(&file.insn_list);
hash_init(file.insn_hash);
file.whitelist = find_section_by_name(file.elf, ".discard.func_stack_frame_non_standard");
- file.rodata = find_section_by_name(file.elf, ".rodata");
file.c_file = find_section_by_name(file.elf, ".comment");
file.ignore_unreachables = no_unreachable;
file.hints = false;