[PATCH] arm64: fix relocation of movz instruction with negative immediate

Dave Martin Dave.Martin at arm.com
Mon Jan 4 10:00:21 PST 2016


On Mon, Jan 04, 2016 at 06:33:03PM +0100, Ard Biesheuvel wrote:
> On 4 January 2016 at 18:21, Dave Martin <Dave.Martin at arm.com> wrote:
> > On Mon, Jan 04, 2016 at 05:09:22PM +0100, Ard Biesheuvel wrote:
> >> The test whether a movz instruction with a signed immediate should be
> >> turned into a movn instruction (i.e., when the immediate is negative)
> >> is flawed, since the value of imm is always positive. So check sval
> >> instead.
> >>
> >> Signed-off-by: Ard Biesheuvel <ard.biesheuvel at linaro.org>
> >> ---
> >>  arch/arm64/kernel/module.c | 2 +-
> >>  1 file changed, 1 insertion(+), 1 deletion(-)
> >>
> >> diff --git a/arch/arm64/kernel/module.c b/arch/arm64/kernel/module.c
> >> index f4bc779e62e8..39e4a29cab50 100644
> >> --- a/arch/arm64/kernel/module.c
> >> +++ b/arch/arm64/kernel/module.c
> >> @@ -128,7 +128,7 @@ static int reloc_insn_movw(enum aarch64_reloc_op op, void *place, u64 val,
> >
> > #define AARCH64_INSN_IMM_MOVNZ          AARCH64_INSN_IMM_MAX
> > #define AARCH64_INSN_IMM_MOVK           AARCH64_INSN_IMM_16
> >
> > /* ... */
> >
> >         if (imm_type == AARCH64_INSN_IMM_MOVNZ) {
> >
> > /* ... */
> >
> >>                * immediate is less than zero.
> >>                */
> >>               insn &= ~(3 << 29);
> >> -             if ((s64)imm >= 0) {
> >> +             if (sval >= 0) {
> >>                       /* >=0: Set the instruction to MOVZ (opcode 10b). */
> >>                       insn |= 2 << 29;
> >>               } else {
> >
> > I _think_ this may be correct, but...
> >
> >                 }
> >                 imm_type = AARCH64_INSN_IMM_MOVK;
> >         }
> >
> >         /* Update the instruction with the new encoding. */
> >         insn = aarch64_insn_encode_immediate(imm_type, insn, imm);
> >
> > /* ... */
> >
> > leaves imm_type as either AARCH64_INSN_IMM_16 or AARCH64_INSN_IMM_MOVK.
> >
> > But because AARCH64_INSN_IMM_16 == AARCH64_INSN_IMM_MOVK (required for , the negative
> > overflow fudge is never applied, no?
> >
> >         if (imm_type != AARCH64_INSN_IMM_16) {
> >                 sval++;
> >                 limit++;
> >         }
> >
> >
> > I'm wondering whether there is a less confusing way to do all this...
> >
> 
> I hadn't spotted that AARCH64_INSN_IMM_16 == AARCH64_INSN_IMM_MOVK, so
> you are correct that my single change is not sufficient to fix this
> code.
> 
> Let me try to come up with something better ..

I think a simpler flow might go something like

	u64 uval = (u64)do_reloc(op, place, val);

	if (is a SABS or PREL reloc that is not _NC, && (uval & (1 << 63))) {
		change insn to MOVN;
		uval = ~uval;
	}

	/* encode the insn using the bottom 16 bits of uval */

	if (not an _NC reloc && (uval >> 16) > 0)
		return -ERANGE;


...or something along those lines.

I haven't tried to implement that yet, though.

Cheers
---Dave



More information about the linux-arm-kernel mailing list