Bug 37698

Summary: optimization compilation error, causing unaligned execptions in the kernel
Product: [Retired] Red Hat Raw Hide Reporter: George France <george.france2>
Component: gccAssignee: Jakub Jelinek <jakub>
Status: CLOSED RAWHIDE QA Contact: David Lawrence <dkl>
Severity: medium Docs Contact:
Priority: medium    
Version: 1.0   
Target Milestone: ---   
Target Release: ---   
Hardware: alpha   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2001-04-27 09:35:28 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:

Description George France 2001-04-25 22:02:49 UTC
Using this compiler: 
Reading specs from /usr/lib/gcc-lib/alpha-redhat-linux/2.96/specs
gcc version 2.96 20000731 (Red Hat Linux 7.1 2.96-81)

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. 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

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.

(This report is being sent to jakab and bugzilla instead of gcc.gnu.org's
GNATS because it refers to Red Hat 7.1 in the gcc -v output)

Will Woods was instrumental in finding problem and reporting it. Please
direct any questions, to Will.Woods.

--George

Comment 1 Jakub Jelinek 2001-04-27 09:35:23 UTC
Should be fixed by:
Tue Jan  2 10:47:38 2001  Richard Kenner  <kenner.nyu.edu>

        * expr.c (store_constructor_field): Update ALIGN before calling
        store_constructor.

This patch was actually in the src.rpm, though only as part of one of a few
%ifarch ia64 patches.
I'm moving it into separate patch and applying unconditionally on all arches
for gcc-2.96-82.

Comment 2 Jakub Jelinek 2001-04-28 18:09:13 UTC
Fixed in gcc-2.96-82.