2

One of my friends asked me this question,and I do else not know the meaning of the function.Maybe like the note above them /* sign-extend to 32 bits */.But I want to know the detail how the function realize role "sign-extend to 32 bits".

The function from Linux kernel. thx all.

Like @unwind said, the complete definition of the function is this:

/* Convert a prel31 symbol to an absolute address */
#define prel31_to_addr(ptr)                         \
({                                                  \
    /* sign-extend to 32 bits */                    \
    long offset = (((long)*(ptr)) << 1) >> 1;       \
    (unsigned long)(ptr) + offset;                  \
})

and it would be used in the function:

int __init unwind_init(void)
{
    struct unwind_idx *idx;

    /* Convert the symbol addresses to absolute values */
    for (idx = __start_unwind_idx; idx < __stop_unwind_idx; idx++)
        idx->addr = prel31_to_addr(&idx->addr);

    pr_debug("unwind: ARM stack unwinding initialised\n");

    return 0;
}
Paolo Moretti
  • 54,162
  • 23
  • 101
  • 92
keyoflov
  • 103
  • 1
  • 6
  • 3
    It's not a function, it's a macro. And the comment above the macro definition actually says: _/* Convert a prel31 symbol to an absolute address */_, which is something specific to the ARM architecture – fork0 Sep 25 '12 at 08:30
  • See http://lxr.free-electrons.com/source/arch/arm/kernel/unwind.c#L94 – fork0 Sep 25 '12 at 08:34
  • thx,Just keep the "specific to the ARM architecture" in mind? – keyoflov Sep 25 '12 at 08:41

2 Answers2

3

Look at where it's called here as an example:

else if ((idx->insn & 0x80000000) == 0)
    /* prel31 to the unwind table */
    ctrl.insn = (unsigned long *)prel31_to_addr(&idx->insn);

so, we know the ptr passed in dereferences to some value whose top (31st) bit is not set. That sort if ties in with the prel31 name, implying only (the low) 31 bits are used in this value.

To convert a signed 31-bit value into a signed 32-bit value, we need to fix up the top bit: there are still only 31 significant bits, but a negative value should have the top bit set. Setting the top bit to match the sign of the existing 31-bit value is sign extension.

By left-shifting one bit, the existing top bit is discarded; when we shift right again, the top bit will be filled to preserve the sign (so it will be 1 if the original 31-bit value was negative, and otherwise zero).

eg. 0x7FFFFFFF is a negative when interpreted as a 31-bit value (-1), but positive when interpreted as a 32-bit value (2,147,483,647). To get a 32-bit encoding with the same meaning as the 31-bit version, we:

  • shift left to discard the un-used top bit: 0x7FFFFFFF << 1 => 0xFFFFFFFE (which is now a negative 32-bit value)
  • shift right again to restore the original pattern in the low 31 bits, but fill the top bit dependent on the sign 0xFFFFFFFE >> 1 => 0xFFFFFFFF = -1

Note this (sign extension) behaviour is platform specific, but then so is all this code. To understand why it makes sense to do all this (rather than simply the meaning of sign extension, and what happens to the bit patterns) you'll need to research the addressing scheme being used.

Daniel Fischer
  • 181,706
  • 17
  • 308
  • 431
Useless
  • 64,155
  • 6
  • 88
  • 132
2

I think this is what it does:

*ptr contains a signed 31bit value, with the sign bit at bit 30 (one less then MSB), so when you shift it left, the sign bit becomes at bit 31 (MSB), when you shift it back to the right, the sign bit will be 'extended' and will show up in bit 30 and bit 31.

So in short: it copies bit 30 to bit 31.

huysentruitw
  • 27,376
  • 9
  • 90
  • 133