This is the mail archive of the
`binutils@sourceware.org`
mailing list for the binutils project.

Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|

Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |

Other format: | [Raw text] |

*From*: "Jan Beulich" <JBeulich at suse dot com>*To*: "Julian Brown" <julian at codesourcery dot com>*Cc*: <binutils at sourceware dot org>*Date*: Thu, 08 Nov 2012 14:02:19 +0000*Subject*: Re: [PATCH] Fix sleb128 encoding for difference expressions*References*: <20121108130512.4991d16a@octopus>

>>> On 08.11.12 at 14:05, Julian Brown <julian@codesourcery.com> wrote: > Hi, > > We encountered a situation where .sleb128 directives would behave in an > unexpected way. For a source file such as: > > .text > .globl foo > foo: > .L1: > .byte 0 > .byte 0 > .byte 0 > .L2: > > .data > bar: > .sleb128 .L1 - .L2 > .byte 42 > > assembled and objdump'd, we get: > > Contents of section .data: > 0000 fdffffff ffffffff ff012a00 00000000 ..........*..... > > the value of "-3" has been interpreted as a (64-bit) unsigned quantity > 0xfffffffffffffffd, and henceforth encoded as a sleb128 value, whereas > what we wanted was simply the encoding "7d", i.e. -3. > > The clause in read.c:emit_leb128_expr is a clue as to why this is > happening: > > else if (op == O_constant > && sign > && (exp->X_add_number < 0) != !exp->X_unsigned) > { > /* We're outputting a signed leb128 and the sign of X_add_number > doesn't reflect the sign of the original value. Convert EXP > to a correctly-extended bignum instead. */ > convert_to_bignum (exp); > op = O_big; > } > > so in this case we have exp->X_add_number less than zero, but > exp->X_unsigned is true: the operands (.L1, .L2) are unsigned, so the > result of the expression .L1 - .L2 is also unsigned. Hence, > convert_to_bignum converts "exp" to a bignum as an unsigned expression. > > My proposed fix is a change to the ad-hoc type system for expressions. > The basic idea is simply to see if the result of a subtraction > operation will fall below zero, and if so force the "unsigned" flag for > the result value to be false (normally all of an expression's operands, > and its result, are unsigned). No other operators are altered. I don't think this will go without surprises here and there: Consider that expressions like a - b + c and a + c - b could now evaluate differently (for appropriately chosen values). I could see your change being correct for the <symbol> - <symbol> case, but certainly not for <constant> - <constant> (<symbol> - <constant> being questionable). > This still works for expressions such as, > > .sleb128 .L2 - .L1 + (1 << 31) > (or .sleb128 .L2 - .L1 + (1 << 63)) > > where L2 is greater than L1, i.e. where the sign bit "looks like" it is > set, since the result of these will still be regarded as unsigned. > There may be other corner cases which behave unexpectedly, however. > > OK to apply, or any comments? Maybe suggestions for other ways of > tackling the problem? (Tested with cross to mips-linux.) I think that the .sleb128 handler itself might instead need to be changed to make the result explicitly signed (as that's what directive says) at least in some specific cases. Jan

**Follow-Ups**:**Re: [PATCH] Fix sleb128 encoding for difference expressions***From:*Julian Brown

**References**:**[PATCH] Fix sleb128 encoding for difference expressions***From:*Julian Brown

Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|

Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |