c/2649: optimization compilation error, causing unaligned execptions on Alpha Linux

france@handhelds.org france@handhelds.org
Wed Apr 25 17:46:00 GMT 2001


>Number:         2649
>Category:       c
>Synopsis:       optimization compilation error, causing unaligned execptions on Alpha Linux
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    unassigned
>State:          open
>Class:          wrong-code
>Submitter-Id:   net
>Arrival-Date:   Wed Apr 25 17:46:00 PDT 2001
>Closed-Date:
>Last-Modified:
>Originator:     George France
>Release:        gcc version 2.96 20000731 (Linux 7.1 2.96-81)
>Organization:
>Environment:
Alpha Linux 2.4.2
>Description:

 The optimizer combines two 32-bit stores (stl) in adjacent memory locations
 (in a struct, for instance) into one 64-bit store (stq) if you're storing
 zeroes. This is fine, unless the two 32-bit locations are not aligned on a
 64-bit boundary. 
>How-To-Repeat:
 This test program shows the problem. 

 #include <stdio.h>

 struct test {
     char *     a;  /* 8 bytes */
     short int  b;  /* 2 bytes */
     int      c[2]; /* 8 bytes */
 };

 int main(int argc, char **argv) {
     struct test t = {argv[0], 0, { 0, 0 } };
     printf("argv[0] is %s\n",t.a);
     return 0;
 }

 Compiled with the following flags, we get an unaligned access:

 gcc -O2 -o test test.c

>Fix:

>Release-Note:
>Audit-Trail:
>Unformatted:
 >./test
  test(2636): unaligned trap at 00000001200005f8: 000000011ffff8fc 2d 31
  argv[0] is ./test
 
  Looking at the assembler source for this program, we see:
 
          .file   1 "test.c"
          .set noat
          .set noreorder
  .section        .rodata
  $LC0:
          .ascii "argv[0] is %s\12\0"
  .text
          .align 4
          .globl main
          .ent main
  main:
          .frame $30,80,$26,0
          .mask 0x4000000,-80
          ldgp $29,0($27)
  $main..ng:
          lda $16,$LC0
          lda $30,-80($30)
          ldq $2,0($17)
          ldl $1,56($30)
          stq $31,60($30) ; <---- problem
          fnop
          ldq $3,64($30)
          mov $2,$17
          zapnot $1,252,$1
          stq $26,0($30)
          .prologue 1
          stq $2,48($30)
          stl $1,56($30)
          ldq $1,56($30)
          stq $3,32($30)
          stq $2,16($30)
          stq $1,24($30)
          jsr $26,printf
          ldgp $29,0($26)
          mov $31,$0
          ldq $26,0($30)
          lda $30,80($30)
          ret $31,($26),1
          .end main
          .ident  "GCC: (GNU) 2.96 20000731 (Red Hat Linux 7.1 2.96-81)"
 
  the line noted above is storing zero ($31) at an offset of 60 from the
  stack pointer ($30).
  60 is not divisible by 8 and thus not 64-bit aligned, so doing a 64-bit
  store (stq) there causes an unaligned memory access exception. This occurs
  in the linux kernel in a few places, notably the nfs3 driver.
 
  If the program is changed so that the two 32-bit variables are assigned
  separately, the following happens:
 
  #include <stdio.h>
 
  struct test {
      char *     a;  /* 8 bytes */
      short int  b;  /* 2 bytes */
      int      c[2]; /* 8 bytes */
  };
 
  int main(int argc, char **argv) {
      struct test t;
      t.a = argv[0];
      t.b = 0;
      t.c[0] = 0;
      t.c[1] = 0;
      printf("argv[0] is %s\n",t.a);
      return 0;
  }
 
  Assembler output:
          .file   1 "test_ok.c"
          .set noat
          .set noreorder
  .section        .rodata
  $LC0:
          .ascii "argv[0] is %s\12\0"
  .text
          .align 4
          .globl main
          .ent main
  main:
          .frame $30,48,$26,0
          .mask 0x4000000,-48
          ldgp $29,0($27)
  $main..ng:
          lda $16,$LC0
          lda $30,-48($30)
          ldq $2,0($17)
          ldl $1,24($30)
          stq $26,0($30)
          .prologue 1
          mov $2,$17
          stl $31,28($30) ; <---- the first 32-bit zero
          zapnot $1,252,$1
          stl $31,32($30) ; <---- the second 32-bit zero
          stq $2,16($30)
          stl $1,24($30)
       jsr $26,printf
          ldgp $29,0($26)
          mov $31,$0
          ldq $26,0($30)
          nop
          lda $30,48($30)
          ret $31,($26),1
          .end main
          .ident  "GCC: (GNU) 2.96 20000731 (Red Hat Linux 7.1 2.96-81)"
 
  Now, in the lines above, the stq has been broken into two stl instructions,
  and no unaligned accesses occur.
 



More information about the Gcc-bugs mailing list