diff --git a/tools/objtool/arch/x86/special.c b/tools/objtool/arch/x86/special.c
index cd964b85e2b1..08a5ce662974 100644
--- a/tools/objtool/arch/x86/special.c
+++ b/tools/objtool/arch/x86/special.c
@@ -112,46 +112,34 @@ static struct reloc *find_switch_table(struct objtool_file *file,
 				       struct instruction *insn,
 				       unsigned long *table_size)
 {
-	struct reloc  *text_reloc, *rodata_reloc;
-	struct section *table_sec;
-	unsigned long table_offset;
-
-	/* look for a relocation which references .rodata */
-	text_reloc = find_reloc_by_dest_range(file->elf, insn->sec,
-					      insn->offset, insn->len);
-	if (!text_reloc || text_reloc->sym->type != STT_SECTION ||
-	    !text_reloc->sym->sec->rodata)
-		return NULL;
-
-	table_offset = reloc_addend(text_reloc);
-	table_sec = text_reloc->sym->sec;
+	struct reloc *rodata_reloc;
+	struct symbol *sym = NULL;
 
-	if (reloc_type(text_reloc) == R_X86_64_PC32)
-		table_offset += 4;
+	/*
+	 * Each table entry has a rela associated with it.  The rela
+	 * should reference text in the same function as the original
+	 * instruction.
+	 */
+	rodata_reloc = find_rodata_sym_reference(file, insn, &sym);
 
 	/*
-	 * Make sure the .rodata address isn't associated with a
-	 * symbol.  GCC jump tables are anonymous data.
+	 * Annotations, if present, are attached to the indirect jump
+	 * instruction directly. In this case, a symbol annotation is
+	 * expected.
+	 *
+	 * Otherwise, make sure the .rodata address isn't associated with
+	 * a symbol. Unannotated GCC jump tables are anonymous data.
 	 *
 	 * Also support C jump tables which are in the same format as
 	 * switch jump tables.  For objtool to recognize them, they
 	 * need to be placed in the C_JUMP_TABLE_SECTION section.  They
 	 * have symbols associated with them.
 	 */
-	if (find_symbol_containing(table_sec, table_offset) &&
-	    strcmp(table_sec->name, C_JUMP_TABLE_SECTION))
-		return NULL;
-
-	/*
-	 * Each table entry has a rela associated with it.  The rela
-	 * should reference text in the same function as the original
-	 * instruction.
-	 */
-	rodata_reloc = find_reloc_by_dest(file->elf, table_sec, table_offset);
-	if (!rodata_reloc)
+	if (insn->type != INSN_JUMP_DYNAMIC && sym &&
+	    strcmp(sym->sec->name, C_JUMP_TABLE_SECTION))
 		return NULL;
 
-	*table_size = 0;
+	*table_size = sym ? sym->len : 0;
 	return rodata_reloc;
 }
 
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 389475dde47c..b923d4a4efcb 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -1372,6 +1372,8 @@ __weak const char *arch_nop_fentry_call(int len)
 
 static struct reloc *insn_reloc(struct objtool_file *file, struct instruction *insn)
 {
+	unsigned long offset = insn->offset;
+	unsigned int len = insn->len;
 	struct reloc *reloc;
 
 	if (insn->no_reloc)
@@ -1380,8 +1382,12 @@ static struct reloc *insn_reloc(struct objtool_file *file, struct instruction *i
 	if (!file)
 		return NULL;
 
-	reloc = find_reloc_by_dest_range(file->elf, insn->sec,
-					 insn->offset, insn->len);
+	do {
+		/* Skip any R_*_NONE relocations */
+		reloc = find_reloc_by_dest_range(file->elf, insn->sec,
+						 offset++, len--);
+	} while (len && reloc && reloc_type(reloc) == R_NONE);
+
 	if (!reloc) {
 		insn->no_reloc = 1;
 		return NULL;
@@ -2169,10 +2175,86 @@ int add_jump_table(struct objtool_file *file, struct instruction *insn,
 	return 0;
 }
 
+struct reloc *find_rodata_sym_reference(struct objtool_file *file,
+					struct instruction *insn,
+					struct symbol **table_sym)
+{
+	struct reloc *text_reloc, *rodata_reloc;
+	unsigned long addend;
+	struct symbol *sym;
+
+	/*
+	 * Look for a relocation which references .rodata. We must use
+	 * find_reloc_by_dest_range() directly here, as insn_reloc() filters
+	 * out R_*_NONE relocations which are used for jump table annotations.
+	 */
+	text_reloc = find_reloc_by_dest_range(file->elf, insn->sec,
+					      insn->offset, insn->len);
+	if (!text_reloc) {
+		insn->no_reloc = 1;
+		return NULL;
+	}
+
+	sym = text_reloc->sym;
+	if (!sym->sec->rodata)
+		return NULL;
+
+	if (reloc_type(text_reloc) == elf_data_rela_type(file->elf))
+		addend = arch_dest_reloc_offset(reloc_addend(text_reloc));
+	else
+		addend = reloc_addend(text_reloc);
+
+	rodata_reloc = find_reloc_by_dest(file->elf, sym->sec,
+					  sym->offset + addend);
+	if (!rodata_reloc)
+		return NULL;
+
+	/*
+	 * Find the ELF symbol covering the destination of the relocation. This
+	 * is trivial if the reloc refers to a STT_OBJECT directly, but it may
+	 * have been emitted as section relative as well.
+	 */
+	if (sym->type == STT_SECTION)
+		sym = find_symbol_containing(sym->sec, addend);
+
+	*table_sym = sym;
+	return rodata_reloc;
+}
+
+/*
+ * Generic version of jump table handling, relying strictly on annotations
+ * provided by the compiler. Overridden for x86 using heuristics that attempt
+ * to correlate indirect jump instructions with preceding .rodata references.
+ */
 int __weak add_func_jump_tables(struct objtool_file *file,
 				struct symbol *func)
 {
-	return 0;
+	struct instruction *insn;
+	int ret = 0;
+
+	func_for_each_insn(file, func, insn) {
+		struct reloc *reloc;
+		struct symbol *sym;
+
+		if (insn->type != INSN_JUMP_DYNAMIC)
+			continue;
+
+		/*
+		 * Look for a relocation attached to this indirect jump that
+		 * references an ELF object in .rodata. This should be the jump
+		 * table annotation emitted by the compiler.
+		 */
+		reloc = find_rodata_sym_reference(file, insn, &sym);
+		if (reloc && sym && sym->len) {
+			insn->_jump_table = reloc;
+			insn->_jump_table_size = sym->len;
+
+			ret = add_jump_table(file, insn, NULL);
+			if (ret)
+				break;
+		}
+	}
+	return ret;
 }
 
 /*
diff --git a/tools/objtool/include/objtool/check.h b/tools/objtool/include/objtool/check.h
index e2f755484c4a..7781100c9340 100644
--- a/tools/objtool/include/objtool/check.h
+++ b/tools/objtool/include/objtool/check.h
@@ -140,4 +140,8 @@ struct instruction *next_insn_same_func(struct objtool_file *file, struct instru
 	     insn;							\
 	     insn = next_insn_same_func(file, insn))
 
+struct reloc *find_rodata_sym_reference(struct objtool_file *file,
+					struct instruction *insn,
+					struct symbol **sym);
+
 #endif /* _CHECK_H */
