Skip to content

Commit 134ab5b

Browse files
author
Peter Zijlstra
committed
objtool,x86: Replace alternatives with .retpoline_sites
Instead of writing complete alternatives, simply provide a list of all the retpoline thunk calls. Then the kernel is free to do with them as it pleases. Simpler code all-round. Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Reviewed-by: Borislav Petkov <[email protected]> Acked-by: Josh Poimboeuf <[email protected]> Tested-by: Alexei Starovoitov <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent c509331 commit 134ab5b

File tree

6 files changed

+107
-252
lines changed

6 files changed

+107
-252
lines changed

arch/x86/kernel/vmlinux.lds.S

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,20 @@ SECTIONS
272272
__parainstructions_end = .;
273273
}
274274

275+
#ifdef CONFIG_RETPOLINE
276+
/*
277+
* List of instructions that call/jmp/jcc to retpoline thunks
278+
* __x86_indirect_thunk_*(). These instructions can be patched along
279+
* with alternatives, after which the section can be freed.
280+
*/
281+
. = ALIGN(8);
282+
.retpoline_sites : AT(ADDR(.retpoline_sites) - LOAD_OFFSET) {
283+
__retpoline_sites = .;
284+
*(.retpoline_sites)
285+
__retpoline_sites_end = .;
286+
}
287+
#endif
288+
275289
/*
276290
* struct alt_inst entries. From the header (alternative.h):
277291
* "Alternative instructions for different CPU types or capabilities"

tools/objtool/arch/x86/decode.c

Lines changed: 0 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -711,126 +711,6 @@ const char *arch_ret_insn(int len)
711711
return ret[len-1];
712712
}
713713

714-
/* asm/alternative.h ? */
715-
716-
#define ALTINSTR_FLAG_INV (1 << 15)
717-
#define ALT_NOT(feat) ((feat) | ALTINSTR_FLAG_INV)
718-
719-
struct alt_instr {
720-
s32 instr_offset; /* original instruction */
721-
s32 repl_offset; /* offset to replacement instruction */
722-
u16 cpuid; /* cpuid bit set for replacement */
723-
u8 instrlen; /* length of original instruction */
724-
u8 replacementlen; /* length of new instruction */
725-
} __packed;
726-
727-
static int elf_add_alternative(struct elf *elf,
728-
struct instruction *orig, struct symbol *sym,
729-
int cpuid, u8 orig_len, u8 repl_len)
730-
{
731-
const int size = sizeof(struct alt_instr);
732-
struct alt_instr *alt;
733-
struct section *sec;
734-
Elf_Scn *s;
735-
736-
sec = find_section_by_name(elf, ".altinstructions");
737-
if (!sec) {
738-
sec = elf_create_section(elf, ".altinstructions",
739-
SHF_ALLOC, 0, 0);
740-
741-
if (!sec) {
742-
WARN_ELF("elf_create_section");
743-
return -1;
744-
}
745-
}
746-
747-
s = elf_getscn(elf->elf, sec->idx);
748-
if (!s) {
749-
WARN_ELF("elf_getscn");
750-
return -1;
751-
}
752-
753-
sec->data = elf_newdata(s);
754-
if (!sec->data) {
755-
WARN_ELF("elf_newdata");
756-
return -1;
757-
}
758-
759-
sec->data->d_size = size;
760-
sec->data->d_align = 1;
761-
762-
alt = sec->data->d_buf = malloc(size);
763-
if (!sec->data->d_buf) {
764-
perror("malloc");
765-
return -1;
766-
}
767-
memset(sec->data->d_buf, 0, size);
768-
769-
if (elf_add_reloc_to_insn(elf, sec, sec->sh.sh_size,
770-
R_X86_64_PC32, orig->sec, orig->offset)) {
771-
WARN("elf_create_reloc: alt_instr::instr_offset");
772-
return -1;
773-
}
774-
775-
if (elf_add_reloc(elf, sec, sec->sh.sh_size + 4,
776-
R_X86_64_PC32, sym, 0)) {
777-
WARN("elf_create_reloc: alt_instr::repl_offset");
778-
return -1;
779-
}
780-
781-
alt->cpuid = bswap_if_needed(cpuid);
782-
alt->instrlen = orig_len;
783-
alt->replacementlen = repl_len;
784-
785-
sec->sh.sh_size += size;
786-
sec->changed = true;
787-
788-
return 0;
789-
}
790-
791-
#define X86_FEATURE_RETPOLINE ( 7*32+12)
792-
793-
int arch_rewrite_retpolines(struct objtool_file *file)
794-
{
795-
struct instruction *insn;
796-
struct reloc *reloc;
797-
struct symbol *sym;
798-
char name[32] = "";
799-
800-
list_for_each_entry(insn, &file->retpoline_call_list, call_node) {
801-
802-
if (insn->type != INSN_JUMP_DYNAMIC &&
803-
insn->type != INSN_CALL_DYNAMIC)
804-
continue;
805-
806-
if (!strcmp(insn->sec->name, ".text.__x86.indirect_thunk"))
807-
continue;
808-
809-
reloc = insn->reloc;
810-
811-
sprintf(name, "__x86_indirect_alt_%s_%s",
812-
insn->type == INSN_JUMP_DYNAMIC ? "jmp" : "call",
813-
reloc->sym->name + 21);
814-
815-
sym = find_symbol_by_name(file->elf, name);
816-
if (!sym) {
817-
sym = elf_create_undef_symbol(file->elf, name);
818-
if (!sym) {
819-
WARN("elf_create_undef_symbol");
820-
return -1;
821-
}
822-
}
823-
824-
if (elf_add_alternative(file->elf, insn, sym,
825-
ALT_NOT(X86_FEATURE_RETPOLINE), 5, 5)) {
826-
WARN("elf_add_alternative");
827-
return -1;
828-
}
829-
}
830-
831-
return 0;
832-
}
833-
834714
int arch_decode_hint_reg(u8 sp_reg, int *base)
835715
{
836716
switch (sp_reg) {

tools/objtool/check.c

Lines changed: 93 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,52 @@ static int create_static_call_sections(struct objtool_file *file)
683683
return 0;
684684
}
685685

686+
static int create_retpoline_sites_sections(struct objtool_file *file)
687+
{
688+
struct instruction *insn;
689+
struct section *sec;
690+
int idx;
691+
692+
sec = find_section_by_name(file->elf, ".retpoline_sites");
693+
if (sec) {
694+
WARN("file already has .retpoline_sites, skipping");
695+
return 0;
696+
}
697+
698+
idx = 0;
699+
list_for_each_entry(insn, &file->retpoline_call_list, call_node)
700+
idx++;
701+
702+
if (!idx)
703+
return 0;
704+
705+
sec = elf_create_section(file->elf, ".retpoline_sites", 0,
706+
sizeof(int), idx);
707+
if (!sec) {
708+
WARN("elf_create_section: .retpoline_sites");
709+
return -1;
710+
}
711+
712+
idx = 0;
713+
list_for_each_entry(insn, &file->retpoline_call_list, call_node) {
714+
715+
int *site = (int *)sec->data->d_buf + idx;
716+
*site = 0;
717+
718+
if (elf_add_reloc_to_insn(file->elf, sec,
719+
idx * sizeof(int),
720+
R_X86_64_PC32,
721+
insn->sec, insn->offset)) {
722+
WARN("elf_add_reloc_to_insn: .retpoline_sites");
723+
return -1;
724+
}
725+
726+
idx++;
727+
}
728+
729+
return 0;
730+
}
731+
686732
static int create_mcount_loc_sections(struct objtool_file *file)
687733
{
688734
struct section *sec;
@@ -1016,6 +1062,11 @@ static void annotate_call_site(struct objtool_file *file,
10161062
return;
10171063
}
10181064

1065+
if (sym->retpoline_thunk) {
1066+
list_add_tail(&insn->call_node, &file->retpoline_call_list);
1067+
return;
1068+
}
1069+
10191070
/*
10201071
* Many compilers cannot disable KCOV with a function attribute
10211072
* so they need a little help, NOP out any KCOV calls from noinstr
@@ -1075,6 +1126,39 @@ static void add_call_dest(struct objtool_file *file, struct instruction *insn,
10751126
annotate_call_site(file, insn, sibling);
10761127
}
10771128

1129+
static void add_retpoline_call(struct objtool_file *file, struct instruction *insn)
1130+
{
1131+
/*
1132+
* Retpoline calls/jumps are really dynamic calls/jumps in disguise,
1133+
* so convert them accordingly.
1134+
*/
1135+
switch (insn->type) {
1136+
case INSN_CALL:
1137+
insn->type = INSN_CALL_DYNAMIC;
1138+
break;
1139+
case INSN_JUMP_UNCONDITIONAL:
1140+
insn->type = INSN_JUMP_DYNAMIC;
1141+
break;
1142+
case INSN_JUMP_CONDITIONAL:
1143+
insn->type = INSN_JUMP_DYNAMIC_CONDITIONAL;
1144+
break;
1145+
default:
1146+
return;
1147+
}
1148+
1149+
insn->retpoline_safe = true;
1150+
1151+
/*
1152+
* Whatever stack impact regular CALLs have, should be undone
1153+
* by the RETURN of the called function.
1154+
*
1155+
* Annotated intra-function calls retain the stack_ops but
1156+
* are converted to JUMP, see read_intra_function_calls().
1157+
*/
1158+
remove_insn_ops(insn);
1159+
1160+
annotate_call_site(file, insn, false);
1161+
}
10781162
/*
10791163
* Find the destination instructions for all jumps.
10801164
*/
@@ -1097,19 +1181,7 @@ static int add_jump_destinations(struct objtool_file *file)
10971181
dest_sec = reloc->sym->sec;
10981182
dest_off = arch_dest_reloc_offset(reloc->addend);
10991183
} else if (reloc->sym->retpoline_thunk) {
1100-
/*
1101-
* Retpoline jumps are really dynamic jumps in
1102-
* disguise, so convert them accordingly.
1103-
*/
1104-
if (insn->type == INSN_JUMP_UNCONDITIONAL)
1105-
insn->type = INSN_JUMP_DYNAMIC;
1106-
else
1107-
insn->type = INSN_JUMP_DYNAMIC_CONDITIONAL;
1108-
1109-
list_add_tail(&insn->call_node,
1110-
&file->retpoline_call_list);
1111-
1112-
insn->retpoline_safe = true;
1184+
add_retpoline_call(file, insn);
11131185
continue;
11141186
} else if (insn->func) {
11151187
/* internal or external sibling call (with reloc) */
@@ -1238,18 +1310,7 @@ static int add_call_destinations(struct objtool_file *file)
12381310
add_call_dest(file, insn, dest, false);
12391311

12401312
} else if (reloc->sym->retpoline_thunk) {
1241-
/*
1242-
* Retpoline calls are really dynamic calls in
1243-
* disguise, so convert them accordingly.
1244-
*/
1245-
insn->type = INSN_CALL_DYNAMIC;
1246-
insn->retpoline_safe = true;
1247-
1248-
list_add_tail(&insn->call_node,
1249-
&file->retpoline_call_list);
1250-
1251-
remove_insn_ops(insn);
1252-
continue;
1313+
add_retpoline_call(file, insn);
12531314

12541315
} else
12551316
add_call_dest(file, insn, reloc->sym, false);
@@ -1980,11 +2041,6 @@ static void mark_rodata(struct objtool_file *file)
19802041
file->rodata = found;
19812042
}
19822043

1983-
__weak int arch_rewrite_retpolines(struct objtool_file *file)
1984-
{
1985-
return 0;
1986-
}
1987-
19882044
static int decode_sections(struct objtool_file *file)
19892045
{
19902046
int ret;
@@ -2057,15 +2113,6 @@ static int decode_sections(struct objtool_file *file)
20572113
if (ret)
20582114
return ret;
20592115

2060-
/*
2061-
* Must be after add_special_section_alts(), since this will emit
2062-
* alternatives. Must be after add_{jump,call}_destination(), since
2063-
* those create the call insn lists.
2064-
*/
2065-
ret = arch_rewrite_retpolines(file);
2066-
if (ret)
2067-
return ret;
2068-
20692116
return 0;
20702117
}
20712118

@@ -3468,6 +3515,13 @@ int check(struct objtool_file *file)
34683515
goto out;
34693516
warnings += ret;
34703517

3518+
if (retpoline) {
3519+
ret = create_retpoline_sites_sections(file);
3520+
if (ret < 0)
3521+
goto out;
3522+
warnings += ret;
3523+
}
3524+
34713525
if (mcount) {
34723526
ret = create_mcount_loc_sections(file);
34733527
if (ret < 0)

0 commit comments

Comments
 (0)