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