[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <CAAhV-H6HxSYGmVoJs9u39biM=D1oa3-T2YSpXdpWkxvUVF-9KA@mail.gmail.com>
Date: Tue, 22 Aug 2023 10:35:08 +0800
From: Huacai Chen <chenhuacai@...nel.org>
To: Tiezhu Yang <yangtiezhu@...ngson.cn>
Cc: Josh Poimboeuf <jpoimboe@...nel.org>,
Peter Zijlstra <peterz@...radead.org>,
loongarch@...ts.linux.dev, linux-kernel@...r.kernel.org,
loongson-kernel@...ts.loongnix.cn
Subject: Re: [PATCH] objtool: Check local label in is_sibling_call() and add_jump_destinations()
Looks good to me.
Reviewed-by: Huacai Chen <chenhuacai@...ngson.cn>
On Tue, Aug 15, 2023 at 4:36 PM Tiezhu Yang <yangtiezhu@...ngson.cn> wrote:
>
> When update the latest upstream gcc and binutils which enables linker
> relaxation by default, it generates more objtool warnings on LoongArch,
> like this:
>
> init/version.o: warning: objtool: early_hostname+0x20: sibling call from callable instruction with modified stack frame
>
> We can see that the branch and jump operation about local label ".L2"
> is not sibling call, because a sibling call is a tail-call to another
> symbol. In this case, make is_sibling_call() return false, set dest_sec
> and dest_off to calculate jump_dest in add_jump_destinations().
>
> Here are some detailed info:
> [fedora@...ux 6.5.test]$ gcc --version
> gcc (GCC) 14.0.0 20230803 (experimental)
> [fedora@...ux 6.5.test]$ as --version
> GNU assembler (GNU Binutils) 2.41.50.20230803
> [fedora@...ux 6.5.test]$ objdump -M no-aliases -D init/version.o
> 0000000000000000 <early_hostname>:
> 0: 00150085 or $a1, $a0, $zero
> 4: 1a000004 pcalau12i $a0, 0
> 8: 02ffc063 addi.d $sp, $sp, -16
> c: 02810406 addi.w $a2, $zero, 65
> 10: 02c00084 addi.d $a0, $a0, 0
> 14: 29c02061 st.d $ra, $sp, 8
> 18: 54000000 bl 0 # 18 <early_hostname+0x18>
> 1c: 0281000c addi.w $t0, $zero, 64
> 20: 6c001584 bgeu $t0, $a0, 20 # 34 <.L2>
> 24: 1a000004 pcalau12i $a0, 0
> 28: 02810005 addi.w $a1, $zero, 64
> 2c: 02c00084 addi.d $a0, $a0, 0
> 30: 54000000 bl 0 # 30 <early_hostname+0x30>
>
> 0000000000000034 <.L2>:
> 34: 28c02061 ld.d $ra, $sp, 8
> 38: 00150004 or $a0, $zero, $zero
> 3c: 02c04063 addi.d $sp, $sp, 16
> 40: 4c000020 jirl $zero, $ra, 0
>
> By the way, it need to move insn_reloc() before is_sibling_call()
> to avoid implicit declaration build error.
>
> Signed-off-by: Tiezhu Yang <yangtiezhu@...ngson.cn>
> ---
> tools/objtool/check.c | 69 ++++++++++++++++++++++++++++++---------------------
> 1 file changed, 41 insertions(+), 28 deletions(-)
>
> diff --git a/tools/objtool/check.c b/tools/objtool/check.c
> index 8936a05..fea3675 100644
> --- a/tools/objtool/check.c
> +++ b/tools/objtool/check.c
> @@ -161,12 +161,39 @@ static bool is_jump_table_jump(struct instruction *insn)
> insn_jump_table(alt_group->orig_group->first_insn);
> }
>
> -static bool is_sibling_call(struct instruction *insn)
> +static struct reloc *insn_reloc(struct objtool_file *file, struct instruction *insn)
> +{
> + struct reloc *reloc;
> +
> + if (insn->no_reloc)
> + return NULL;
> +
> + if (!file)
> + return NULL;
> +
> + reloc = find_reloc_by_dest_range(file->elf, insn->sec,
> + insn->offset, insn->len);
> + if (!reloc) {
> + insn->no_reloc = 1;
> + return NULL;
> + }
> +
> + return reloc;
> +}
> +
> +static bool is_sibling_call(struct objtool_file *file, struct instruction *insn)
> {
> /*
> * Assume only STT_FUNC calls have jump-tables.
> */
> if (insn_func(insn)) {
> + struct reloc *reloc = insn_reloc(file, insn);
> +
> + /* Disallow sibling calls into STT_NOTYPE if it is local lable */
> + if (reloc && reloc->sym->type == STT_NOTYPE &&
> + strncmp(reloc->sym->name, ".L", 2) == 0)
> + return false;
> +
> /* An indirect jump is either a sibling call or a jump to a table. */
> if (insn->type == INSN_JUMP_DYNAMIC)
> return !is_jump_table_jump(insn);
> @@ -232,7 +259,7 @@ static bool __dead_end_function(struct objtool_file *file, struct symbol *func,
> * of the sibling call returns.
> */
> func_for_each_insn(file, func, insn) {
> - if (is_sibling_call(insn)) {
> + if (is_sibling_call(file, insn)) {
> struct instruction *dest = insn->jump_dest;
>
> if (!dest)
> @@ -743,7 +770,7 @@ static int create_static_call_sections(struct objtool_file *file)
> if (!elf_init_reloc_data_sym(file->elf, sec,
> idx * sizeof(*site) + 4,
> (idx * 2) + 1, key_sym,
> - is_sibling_call(insn) * STATIC_CALL_SITE_TAIL))
> + is_sibling_call(file, insn) * STATIC_CALL_SITE_TAIL))
> return -1;
>
> idx++;
> @@ -1298,26 +1325,6 @@ __weak bool arch_is_rethunk(struct symbol *sym)
> return false;
> }
>
> -static struct reloc *insn_reloc(struct objtool_file *file, struct instruction *insn)
> -{
> - struct reloc *reloc;
> -
> - if (insn->no_reloc)
> - return NULL;
> -
> - if (!file)
> - return NULL;
> -
> - reloc = find_reloc_by_dest_range(file->elf, insn->sec,
> - insn->offset, insn->len);
> - if (!reloc) {
> - insn->no_reloc = 1;
> - return NULL;
> - }
> -
> - return reloc;
> -}
> -
> static void remove_insn_ops(struct instruction *insn)
> {
> struct stack_op *op, *next;
> @@ -1560,8 +1567,14 @@ static int add_jump_destinations(struct objtool_file *file)
> * External sibling call or internal sibling call with
> * STT_FUNC reloc.
> */
> - add_call_dest(file, insn, reloc->sym, true);
> - continue;
> + if (reloc->sym->type == STT_NOTYPE &&
> + strncmp(reloc->sym->name, ".L", 2) == 0) {
> + dest_sec = insn->sec;
> + dest_off = arch_jump_destination(insn);
> + } else {
> + add_call_dest(file, insn, reloc->sym, true);
> + continue;
> + }
> } else if (reloc->sym->sec->idx) {
> dest_sec = reloc->sym->sec;
> dest_off = reloc->sym->sym.st_value +
> @@ -3649,7 +3662,7 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
>
> case INSN_JUMP_CONDITIONAL:
> case INSN_JUMP_UNCONDITIONAL:
> - if (is_sibling_call(insn)) {
> + if (is_sibling_call(file, insn)) {
> ret = validate_sibling_call(file, insn, &state);
> if (ret)
> return ret;
> @@ -3670,7 +3683,7 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
>
> case INSN_JUMP_DYNAMIC:
> case INSN_JUMP_DYNAMIC_CONDITIONAL:
> - if (is_sibling_call(insn)) {
> + if (is_sibling_call(file, insn)) {
> ret = validate_sibling_call(file, insn, &state);
> if (ret)
> return ret;
> @@ -3834,7 +3847,7 @@ static int validate_unret(struct objtool_file *file, struct instruction *insn)
>
> case INSN_JUMP_UNCONDITIONAL:
> case INSN_JUMP_CONDITIONAL:
> - if (!is_sibling_call(insn)) {
> + if (!is_sibling_call(file, insn)) {
> if (!insn->jump_dest) {
> WARN_INSN(insn, "unresolved jump target after linking?!?");
> return -1;
> --
> 2.1.0
>
>
Powered by blists - more mailing lists