aboutsummaryrefslogtreecommitdiffstats
path: root/tools/objtool
diff options
context:
space:
mode:
authorAllan Xavier <allan.x.xavier@oracle.com>2018-09-07 09:12:01 -0400
committerThomas Gleixner <tglx@linutronix.de>2018-09-08 06:33:01 -0400
commit4a60aa05a0634241ce17f957bf9fb5ac1eed6576 (patch)
treea2d6485ec7019385179eaf6c526cd9ab87dcd193 /tools/objtool
parentdb44bf4b4768a0664d3c9d9000ecb747de31ded8 (diff)
objtool: Support per-function rodata sections
Add support for processing switch jump tables in objects with multiple .rodata sections, such as those created by '-ffunction-sections' and '-fdata-sections'. Currently, objtool always looks in .rodata for jump table information, which results in many "sibling call from callable instruction with modified stack frame" warnings with objects compiled using those flags. The fix is comprised of three parts: 1. Flagging all .rodata sections when importing ELF information for easier checking later. 2. Keeping a reference to the section each relocation is from in order to get the list_head for the other relocations in that section. 3. Finding jump tables by following relocations to .rodata sections, rather than always referencing a single global .rodata section. The patch has been tested without data sections enabled and no differences in the resulting orc unwind information were seen. Note that as objtool adds terminators to end of each .text section the unwind information generated between a function+data sections build and a normal build aren't directly comparable. Manual inspection suggests that objtool is now generating the correct information, or at least making more of an effort to do so than it did previously. Signed-off-by: Allan Xavier <allan.x.xavier@oracle.com> Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Link: https://lkml.kernel.org/r/099bdc375195c490dda04db777ee0b95d566ded1.1536325914.git.jpoimboe@redhat.com
Diffstat (limited to 'tools/objtool')
-rw-r--r--tools/objtool/check.c38
-rw-r--r--tools/objtool/check.h4
-rw-r--r--tools/objtool/elf.c1
-rw-r--r--tools/objtool/elf.h3
4 files changed, 37 insertions, 9 deletions
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 2928939b98ec..0414a0d52262 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -836,7 +836,7 @@ static int add_switch_table(struct objtool_file *file, struct instruction *insn,
836 struct symbol *pfunc = insn->func->pfunc; 836 struct symbol *pfunc = insn->func->pfunc;
837 unsigned int prev_offset = 0; 837 unsigned int prev_offset = 0;
838 838
839 list_for_each_entry_from(rela, &file->rodata->rela->rela_list, list) { 839 list_for_each_entry_from(rela, &table->rela_sec->rela_list, list) {
840 if (rela == next_table) 840 if (rela == next_table)
841 break; 841 break;
842 842
@@ -926,6 +926,7 @@ static struct rela *find_switch_table(struct objtool_file *file,
926{ 926{
927 struct rela *text_rela, *rodata_rela; 927 struct rela *text_rela, *rodata_rela;
928 struct instruction *orig_insn = insn; 928 struct instruction *orig_insn = insn;
929 struct section *rodata_sec;
929 unsigned long table_offset; 930 unsigned long table_offset;
930 931
931 /* 932 /*
@@ -953,10 +954,13 @@ static struct rela *find_switch_table(struct objtool_file *file,
953 /* look for a relocation which references .rodata */ 954 /* look for a relocation which references .rodata */
954 text_rela = find_rela_by_dest_range(insn->sec, insn->offset, 955 text_rela = find_rela_by_dest_range(insn->sec, insn->offset,
955 insn->len); 956 insn->len);
956 if (!text_rela || text_rela->sym != file->rodata->sym) 957 if (!text_rela || text_rela->sym->type != STT_SECTION ||
958 !text_rela->sym->sec->rodata)
957 continue; 959 continue;
958 960
959 table_offset = text_rela->addend; 961 table_offset = text_rela->addend;
962 rodata_sec = text_rela->sym->sec;
963
960 if (text_rela->type == R_X86_64_PC32) 964 if (text_rela->type == R_X86_64_PC32)
961 table_offset += 4; 965 table_offset += 4;
962 966
@@ -964,10 +968,10 @@ static struct rela *find_switch_table(struct objtool_file *file,
964 * Make sure the .rodata address isn't associated with a 968 * Make sure the .rodata address isn't associated with a
965 * symbol. gcc jump tables are anonymous data. 969 * symbol. gcc jump tables are anonymous data.
966 */ 970 */
967 if (find_symbol_containing(file->rodata, table_offset)) 971 if (find_symbol_containing(rodata_sec, table_offset))
968 continue; 972 continue;
969 973
970 rodata_rela = find_rela_by_dest(file->rodata, table_offset); 974 rodata_rela = find_rela_by_dest(rodata_sec, table_offset);
971 if (rodata_rela) { 975 if (rodata_rela) {
972 /* 976 /*
973 * Use of RIP-relative switch jumps is quite rare, and 977 * Use of RIP-relative switch jumps is quite rare, and
@@ -1052,7 +1056,7 @@ static int add_switch_table_alts(struct objtool_file *file)
1052 struct symbol *func; 1056 struct symbol *func;
1053 int ret; 1057 int ret;
1054 1058
1055 if (!file->rodata || !file->rodata->rela) 1059 if (!file->rodata)
1056 return 0; 1060 return 0;
1057 1061
1058 for_each_sec(file, sec) { 1062 for_each_sec(file, sec) {
@@ -1198,10 +1202,33 @@ static int read_retpoline_hints(struct objtool_file *file)
1198 return 0; 1202 return 0;
1199} 1203}
1200 1204
1205static void mark_rodata(struct objtool_file *file)
1206{
1207 struct section *sec;
1208 bool found = false;
1209
1210 /*
1211 * This searches for the .rodata section or multiple .rodata.func_name
1212 * sections if -fdata-sections is being used. The .str.1.1 and .str.1.8
1213 * rodata sections are ignored as they don't contain jump tables.
1214 */
1215 for_each_sec(file, sec) {
1216 if (!strncmp(sec->name, ".rodata", 7) &&
1217 !strstr(sec->name, ".str1.")) {
1218 sec->rodata = true;
1219 found = true;
1220 }
1221 }
1222
1223 file->rodata = found;
1224}
1225
1201static int decode_sections(struct objtool_file *file) 1226static int decode_sections(struct objtool_file *file)
1202{ 1227{
1203 int ret; 1228 int ret;
1204 1229
1230 mark_rodata(file);
1231
1205 ret = decode_instructions(file); 1232 ret = decode_instructions(file);
1206 if (ret) 1233 if (ret)
1207 return ret; 1234 return ret;
@@ -2171,7 +2198,6 @@ int check(const char *_objname, bool orc)
2171 INIT_LIST_HEAD(&file.insn_list); 2198 INIT_LIST_HEAD(&file.insn_list);
2172 hash_init(file.insn_hash); 2199 hash_init(file.insn_hash);
2173 file.whitelist = find_section_by_name(file.elf, ".discard.func_stack_frame_non_standard"); 2200 file.whitelist = find_section_by_name(file.elf, ".discard.func_stack_frame_non_standard");
2174 file.rodata = find_section_by_name(file.elf, ".rodata");
2175 file.c_file = find_section_by_name(file.elf, ".comment"); 2201 file.c_file = find_section_by_name(file.elf, ".comment");
2176 file.ignore_unreachables = no_unreachable; 2202 file.ignore_unreachables = no_unreachable;
2177 file.hints = false; 2203 file.hints = false;
diff --git a/tools/objtool/check.h b/tools/objtool/check.h
index 95700a2bcb7c..e6e8a655b556 100644
--- a/tools/objtool/check.h
+++ b/tools/objtool/check.h
@@ -60,8 +60,8 @@ struct objtool_file {
60 struct elf *elf; 60 struct elf *elf;
61 struct list_head insn_list; 61 struct list_head insn_list;
62 DECLARE_HASHTABLE(insn_hash, 16); 62 DECLARE_HASHTABLE(insn_hash, 16);
63 struct section *rodata, *whitelist; 63 struct section *whitelist;
64 bool ignore_unreachables, c_file, hints; 64 bool ignore_unreachables, c_file, hints, rodata;
65}; 65};
66 66
67int check(const char *objname, bool orc); 67int check(const char *objname, bool orc);
diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index 7ec85d567598..f7082de1ee82 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -379,6 +379,7 @@ static int read_relas(struct elf *elf)
379 rela->offset = rela->rela.r_offset; 379 rela->offset = rela->rela.r_offset;
380 symndx = GELF_R_SYM(rela->rela.r_info); 380 symndx = GELF_R_SYM(rela->rela.r_info);
381 rela->sym = find_symbol_by_index(elf, symndx); 381 rela->sym = find_symbol_by_index(elf, symndx);
382 rela->rela_sec = sec;
382 if (!rela->sym) { 383 if (!rela->sym) {
383 WARN("can't find rela entry symbol %d for %s", 384 WARN("can't find rela entry symbol %d for %s",
384 symndx, sec->name); 385 symndx, sec->name);
diff --git a/tools/objtool/elf.h b/tools/objtool/elf.h
index de5cd2ddded9..bc97ed86b9cd 100644
--- a/tools/objtool/elf.h
+++ b/tools/objtool/elf.h
@@ -48,7 +48,7 @@ struct section {
48 char *name; 48 char *name;
49 int idx; 49 int idx;
50 unsigned int len; 50 unsigned int len;
51 bool changed, text; 51 bool changed, text, rodata;
52}; 52};
53 53
54struct symbol { 54struct symbol {
@@ -68,6 +68,7 @@ struct rela {
68 struct list_head list; 68 struct list_head list;
69 struct hlist_node hash; 69 struct hlist_node hash;
70 GElf_Rela rela; 70 GElf_Rela rela;
71 struct section *rela_sec;
71 struct symbol *sym; 72 struct symbol *sym;
72 unsigned int type; 73 unsigned int type;
73 unsigned long offset; 74 unsigned long offset;