lkml.org 
[lkml]   [2018]   [Jan]   [18]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    From
    Subject[PATCH 18/35] objtool: Another static block fail
    I've observed GCC generate:

    sym:
    NOP/JMP 1f (static_branch)
    JMP 2f
    1: /* crud */
    JMP 3f
    2: /* other crud */

    3: RETQ


    This means we need to follow unconditional jumps; be conservative and
    only follow if its a unique jump.

    (I've not yet figured out which CONFIG option is responsible for this,
    a normal defconfig build does not generate crap like this)

    Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
    ---
    tools/objtool/check.c | 33 +++++++++++++++++++++++++++++++--
    tools/objtool/check.h | 3 ++-
    2 files changed, 33 insertions(+), 3 deletions(-)

    --- a/tools/objtool/check.c
    +++ b/tools/objtool/check.c
    @@ -521,7 +521,7 @@ static int add_jump_destinations(struct
    return -1;
    }

    - insn->jump_dest->branch_target = true;
    + insn->jump_dest->branch_target++;
    }

    return 0;
    @@ -1207,6 +1207,8 @@ static int read_retpoline_hints(struct o
    return 0;
    }

    +static void jmp_grow_static_block(struct objtool_file *file, struct instruction *insn);
    +
    static bool __grow_static_block(struct objtool_file *file,
    struct instruction *insn, bool ign_bt)
    {
    @@ -1216,7 +1218,8 @@ static bool __grow_static_block(struct o

    switch (insn->type) {
    case INSN_JUMP_UNCONDITIONAL:
    - /* mark this instruction, terminate this section */
    + /* follow the jump, mark this instruction, terminate this section */
    + jmp_grow_static_block(file, insn->jump_dest);
    insn->static_jump_dest = true;
    return false;

    @@ -1238,6 +1241,32 @@ static bool __grow_static_block(struct o
    return true;
    }

    +static void jmp_grow_static_block(struct objtool_file *file, struct instruction *insn)
    +{
    + bool ignore = true;
    +
    + /* !jump_dest */
    + if (!insn)
    + return;
    +
    + /* more than a single site jumps here, can't be certain */
    + if (insn->branch_target > 1)
    + return;
    +
    + for (; &insn->list != &file->insn_list;
    + insn = list_next_entry(insn, list)) {
    +
    + /*
    + * Per definition the first insn of a jump is a branch target,
    + * don't terminate because of that.
    + */
    + if (!__grow_static_block(file, insn, ignore))
    + break;
    +
    + ignore = false;
    + }
    +}
    +
    static int grow_static_blocks(struct objtool_file *file)
    {
    bool static_block = false;
    --- a/tools/objtool/check.h
    +++ b/tools/objtool/check.h
    @@ -45,7 +45,8 @@ struct instruction {
    unsigned char type;
    unsigned long immediate;
    bool alt_group, visited, dead_end, ignore, hint, save, restore, ignore_alts;
    - bool static_jump_dest, retpoline_safe, branch_target;
    + bool static_jump_dest, retpoline_safe;
    + int branch_target;
    struct symbol *call_dest;
    struct instruction *jump_dest;
    struct list_head alts;

    \
     
     \ /
      Last update: 2018-01-18 15:58    [W:4.727 / U:0.168 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site