[Linux-Xtensa] Re: sched_clock always 0 and no process time accounting with 3.11-rc1

Baruch Siach baruch at tkos.co.il
Wed Jul 17 01:13:46 PDT 2013


On Wed, Jul 17, 2013 at 12:52:34AM -0700, Chris Zankel wrote:
> HI Baruch,
> 
> It's actually a problem in binutils, and I haven't checked if a fix has
> been included recently.
> 
> What happens is that negative offsets become huge values on 64-bit
> hosts, so the emitted relocation entry has a large positive offset
> instead of negative offset. I saw this problem with glibc's  vfprintf

So this is the cause of the following warnings that I see when building the 
kernel:

arch/xtensa/mm/misc.S: Assembler messages:
arch/xtensa/mm/misc.S:143: Warning: value 0xffffffff30000106 truncated to 0x30000106
arch/xtensa/mm/misc.S:197: Warning: value 0xffffffff30000106 truncated to 0x30000106

for the following assembly line:

    movi    a4, -PAGE_OFFSET + (PAGE_KERNEL | _PAGE_HW_WRITE)

The -PAGE_OFFSET constant is promoted to 64 bit, which is contrary to the 
documented behaviour of gas (binutils 2.22, user guide section 3.6.2).

> BTW, do you have write access to the Wiki?

No. What should I do to get access?

> This was my original analysis. Reading it again, I'm not sure if I still 
> understand what I wrote ;-)

Should your attached patch fix the issue?

baruch

> Turned out that the code
> doesn't support 'negative' diffs. This exacerbates for 64-bit hosts (but
> I think it also exists on 32-bit hosts for DIFF8 and DIFF16). Diffs are
> 'unsigned' so calculated offsets become larger(!) instead of smaller.
> 
> The code in question first calculates the original end address (=
> original start address + diff) before applying relaxation, and then
> determines the new start address and difference from the new start and
> end address after subtracting relaxation bytes for each:
> 
> new_end_offset = offset_with_removed_text
> (&target_relax_info->action_list, r_rel.target_offset + diff_value);
> diff_value = new_end_offset - new_reloc.target_offset;
> 
> The function offset_with_removed_text adds relaxation bytes as long as
> this condition is met:
> 
> if (r->offset > offset)
>   break;
> ...
> removed += r->removed_bytes;
> 
> For example, with an address of 0x100 and an 8-bit diff of 0xf0, the
> address that's checked in the function offset_with_removed_text()
> becomes 0x1f0 (instead of 0x10), so the loop goes way beyond 0x10 and
> adds additional 'removed_bytes'.
> 
> 
> On 07/17/2013 12:14 AM, Baruch Siach wrote:
> > Hi Chris,
> >
> > On Wed, Jul 17, 2013 at 12:02:10AM -0700, Chris Zankel wrote:
> >> On 07/16/2013 11:47 PM, Baruch Siach wrote:
> >>>> According to C99 the behaviour of (1 << 32) is undefined on platforms with
> >>>> 32 bit int, so it could yield any value.
> >>> But so is ARM, isn't it?
> >> The handling of constants might be target-architecture dependent.
> >>
> >> On a somewhat related issue, are you using a 32-bit host or 64-bit host?
> >> Note that 64-bit cross compilation is known to be broken for Xtensa, I
> >> had a problem running glibc when compiled with cross compiler on a
> >> 64-bit host.
> > Yes, my host is x86_64. I haven't encountered any problem yet. But thanks for 
> > the warning, I'll keep that in mind. I think it's worth a mention in the 
> > linux-xtensa wiki. It surly worth a fix as well, I guess. Are there any 
> > samples of code that are known to be break with 64 bit host?
> >
> > baruch

> --- /home/czankel/Work/Xtensa/CrosstoolNg/xtools/crosstool-NG/.build/src/binutils-2.21.1a/bfd/elf32-xtensa.c	2010-10-25 08:54:14.000000000 -0700
> +++ ./elf32-xtensa.c	2013-02-04 17:42:58.336394499 -0800
> @@ -9029,14 +9029,17 @@
>  		  switch (r_type)
>  		    {
>  		    case R_XTENSA_DIFF8:
> +		      diff_mask = 0xff;
>  		      diff_value =
>  			bfd_get_8 (abfd, &contents[old_source_offset]);
>  		      break;
>  		    case R_XTENSA_DIFF16:
> +		      diff_mask = 0xffff;
>  		      diff_value =
>  			bfd_get_16 (abfd, &contents[old_source_offset]);
>  		      break;
>  		    case R_XTENSA_DIFF32:
> +		      diff_mask = 0xffffffff;
>  		      diff_value =
>  			bfd_get_32 (abfd, &contents[old_source_offset]);
>  		      break;
> @@ -9044,23 +9047,21 @@
>  
>  		  new_end_offset = offset_with_removed_text
>  		    (&target_relax_info->action_list,
> -		     r_rel.target_offset + diff_value);
> +		     (r_rel.target_offset + diff_value) & diff_mask);
>  		  diff_value = new_end_offset - new_reloc.target_offset;
> +		  diff_value &= diff_mask;
>  
>  		  switch (r_type)
>  		    {
>  		    case R_XTENSA_DIFF8:
> -		      diff_mask = 0xff;
>  		      bfd_put_8 (abfd, diff_value,
>  				 &contents[old_source_offset]);
>  		      break;
>  		    case R_XTENSA_DIFF16:
> -		      diff_mask = 0xffff;
>  		      bfd_put_16 (abfd, diff_value,
>  				  &contents[old_source_offset]);
>  		      break;
>  		    case R_XTENSA_DIFF32:
> -		      diff_mask = 0xffffffff;
>  		      bfd_put_32 (abfd, diff_value,
>  				  &contents[old_source_offset]);
>  		      break;


-- 
     http://baruch.siach.name/blog/                  ~. .~   Tk Open Systems
=}------------------------------------------------ooO--U--Ooo------------{=
   - baruch at tkos.co.il - tel: +972.2.679.5364, http://www.tkos.co.il -


More information about the linux-xtensa mailing list