diff options
author | Peter Zijlstra <peterz@infradead.org> | 2020-08-18 15:57:49 +0200 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2020-09-01 09:58:06 +0200 |
commit | 5b06fd3bb9cdce4f3e731c48eb5b74c4acc47997 (patch) | |
tree | 533fcad5bdd98fd31ccd3956dec2e3478f15ca91 /tools/objtool | |
parent | 452cddbff74b6a15b9354505671011700fe03710 (diff) | |
download | linux-5b06fd3bb9cdce4f3e731c48eb5b74c4acc47997.tar.gz linux-5b06fd3bb9cdce4f3e731c48eb5b74c4acc47997.tar.bz2 linux-5b06fd3bb9cdce4f3e731c48eb5b74c4acc47997.zip |
static_call: Handle tail-calls
GCC can turn our static_call(name)(args...) into a tail call, in which
case we get a JMP.d32 into the trampoline (which then does a further
tail-call).
Teach objtool to recognise and mark these in .static_call_sites and
adjust the code patching to deal with this.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Link: https://lore.kernel.org/r/20200818135805.101186767@infradead.org
Diffstat (limited to 'tools/objtool')
-rw-r--r-- | tools/objtool/check.c | 18 |
1 files changed, 13 insertions, 5 deletions
diff --git a/tools/objtool/check.c b/tools/objtool/check.c index f8f7a40c6ef3..75d0cd2f9044 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -516,7 +516,7 @@ static int create_static_call_sections(struct objtool_file *file) } memset(reloc, 0, sizeof(*reloc)); reloc->sym = key_sym; - reloc->addend = 0; + reloc->addend = is_sibling_call(insn) ? STATIC_CALL_SITE_TAIL : 0; reloc->type = R_X86_64_PC32; reloc->offset = idx * sizeof(struct static_call_site) + 4; reloc->sec = reloc_sec; @@ -747,6 +747,10 @@ static int add_jump_destinations(struct objtool_file *file) } else { /* external sibling call */ insn->call_dest = reloc->sym; + if (insn->call_dest->static_call_tramp) { + list_add_tail(&insn->static_call_node, + &file->static_call_list); + } continue; } @@ -798,6 +802,10 @@ static int add_jump_destinations(struct objtool_file *file) /* internal sibling call */ insn->call_dest = insn->jump_dest->func; + if (insn->call_dest->static_call_tramp) { + list_add_tail(&insn->static_call_node, + &file->static_call_list); + } } } } @@ -1684,6 +1692,10 @@ static int decode_sections(struct objtool_file *file) if (ret) return ret; + ret = read_static_call_tramps(file); + if (ret) + return ret; + ret = add_jump_destinations(file); if (ret) return ret; @@ -1716,10 +1728,6 @@ static int decode_sections(struct objtool_file *file) if (ret) return ret; - ret = read_static_call_tramps(file); - if (ret) - return ret; - return 0; } |