public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH, libiberty] Fix segfault in floatformat.c:get_field on 64-bit  hosts
@ 2006-06-09 16:58 Julian Brown
  2006-06-13 16:45 ` Ian Lance Taylor
  0 siblings, 1 reply; 8+ messages in thread
From: Julian Brown @ 2006-06-09 16:58 UTC (permalink / raw)
  To: binutils; +Cc: GCC Patches, DJ Delorie

[-- Attachment #1: Type: text/plain, Size: 790 bytes --]

Hi,

This patch fixes a problem with floatformat.c:get_field on 64-bit (on at 
least x86_64), when cross-assembling to arm-none-eabi. The line which reads:

   result = *(data + cur_byte) >> (-cur_bitshift);

was executed with cur_byte = -1 (start + len == 0 and order == 
floatformat_little), which happily segfaulted (during printing of FP 
immediates).

I had a little trouble following the logic of the function, so this is 
basically a rewrite. I hope that's OK.

Tested with cross (binutils) to arm-none-eabi from 
powerpc64-unknown-linux-gnu (i.e. big-endian) and 
x86_64-unknown-linux-gnu (i.e. little-endian). OK to apply?

Cheers,

Julian

ChangeLog:

     * floatformat.c (get_field): Fix segfault with little-endian word
     order on 64-bit hosts.
     (min): Move definition.

[-- Attachment #2: libiberty-getfield-2 --]
[-- Type: text/plain, Size: 3746 bytes --]

Index: libiberty/floatformat.c
===================================================================
RCS file: /cvs/src/src/libiberty/floatformat.c,v
retrieving revision 1.19.6.1
diff -c -p -r1.19.6.1 floatformat.c
*** libiberty/floatformat.c	24 Apr 2006 21:37:24 -0000	1.19.6.1
--- libiberty/floatformat.c	24 May 2006 12:51:20 -0000
*************** const struct floatformat floatformat_ia6
*** 249,301 ****
    floatformat_always_valid
  };
  \f
  /* Extract a field which starts at START and is LEN bits long.  DATA and
     TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER.  */
  static unsigned long
  get_field (const unsigned char *data, enum floatformat_byteorders order,
             unsigned int total_len, unsigned int start, unsigned int len)
  {
!   unsigned long result;
    unsigned int cur_byte;
!   int cur_bitshift;
  
    /* Start at the least significant part of the field.  */
-   cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT;
    if (order == floatformat_little)
!     cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) - cur_byte - 1;
!   cur_bitshift =
!     ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT;
!   result = *(data + cur_byte) >> (-cur_bitshift);
!   cur_bitshift += FLOATFORMAT_CHAR_BIT;
!   if (order == floatformat_little)
!     ++cur_byte;
    else
!     --cur_byte;
  
!   /* Move towards the most significant part of the field.  */
!   while ((unsigned int) cur_bitshift < len)
      {
!       if (len - cur_bitshift < FLOATFORMAT_CHAR_BIT)
! 	/* This is the last byte; zero out the bits which are not part of
! 	   this field.  */
! 	result |=
! 	  (*(data + cur_byte) & ((1 << (len - cur_bitshift)) - 1))
! 	    << cur_bitshift;
!       else
! 	result |= *(data + cur_byte) << cur_bitshift;
!       cur_bitshift += FLOATFORMAT_CHAR_BIT;
!       if (order == floatformat_little)
! 	++cur_byte;
!       else
! 	--cur_byte;
      }
!   return result;
  }
    
- #ifndef min
- #define min(a, b) ((a) < (b) ? (a) : (b))
- #endif
- 
  /* Convert from FMT to a double.
     FROM is the address of the extended float.
     Store the double in *TO.  */
--- 249,299 ----
    floatformat_always_valid
  };
  \f
+ 
+ #ifndef min
+ #define min(a, b) ((a) < (b) ? (a) : (b))
+ #endif
+ 
  /* Extract a field which starts at START and is LEN bits long.  DATA and
     TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER.  */
  static unsigned long
  get_field (const unsigned char *data, enum floatformat_byteorders order,
             unsigned int total_len, unsigned int start, unsigned int len)
  {
!   unsigned long result = 0;
    unsigned int cur_byte;
!   int lo_bit, hi_bit, cur_bitshift = 0;
!   int nextbyte = (order == floatformat_little) ? 1 : -1;
! 
!   /* Start is in big-endian bit order!  Fix that first.  */
!   start = total_len - (start + len);
  
    /* Start at the least significant part of the field.  */
    if (order == floatformat_little)
!     cur_byte = start / FLOATFORMAT_CHAR_BIT;
    else
!     cur_byte = (total_len - start - 1) / FLOATFORMAT_CHAR_BIT;
  
!   lo_bit = start % FLOATFORMAT_CHAR_BIT;
!   hi_bit = min (lo_bit + len, FLOATFORMAT_CHAR_BIT);
!   
!   do
      {
!       unsigned int shifted = *(data + cur_byte) >> lo_bit;
!       unsigned int bits = hi_bit - lo_bit;
!       unsigned int mask = (1 << bits) - 1;
!       result |= (shifted & mask) << cur_bitshift;
!       len -= bits;
!       cur_bitshift += bits;
!       cur_byte += nextbyte;
!       lo_bit = 0;
!       hi_bit = min (len, FLOATFORMAT_CHAR_BIT);
      }
!   while (len != 0);
! 
!   return result & ((2 << (total_len - 1)) - 1);
  }
    
  /* Convert from FMT to a double.
     FROM is the address of the extended float.
     Store the double in *TO.  */

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2006-11-07 15:21 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-06-09 16:58 [PATCH, libiberty] Fix segfault in floatformat.c:get_field on 64-bit hosts Julian Brown
2006-06-13 16:45 ` Ian Lance Taylor
2006-06-13 17:23   ` Julian Brown
2006-06-14  2:44     ` Ian Lance Taylor
2006-06-15 22:46       ` Julian Brown
2006-07-21  5:36         ` Mark Mitchell
2006-07-21 16:33         ` Ian Lance Taylor
2006-11-07 15:21           ` Julian Brown

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).