[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#676558: gcc-4.6: Incorrect assembly code generated for loop over char ** in named sections



Package: gcc-4.6
Version: 4.6.3-1
Severity: normal

Dear Maintainer,

I have a program that loops over const char * pointers in named sections.
In this loop, incorrect generated assembly code causes wrong output, e.g.
it outputs (null) instead of the string pointed to by the const char * pointer.
This (null) can be tracked down to the generated assembly code where it
puts a static zero on the stack instead of the address of the string.

This incorrect code is generated for 32 bit with optimization levels 1-3
only. 64 bit is not affected, neither is unoptimized 32 bit.

I found various versions of gcc 4.6.x containing this bug, including:
TDM-GCC 4.6.1, MinGW gcc 4.6.2 and Debian gcc 4.6.3-1
so it seems to me it is a 4.6 issue. I can confirm that neither MinGW gcc 4.5.2
nor Debian gcc 4.4.5 (Debian Squeeze) contain this bug.

I already filed a bug against TDM-GCC 4.6.1:
http://sourceforge.net/tracker/?func=detail&aid=3532366&group_id=200665&atid=974439

Quoting from this bug report:
===== quote begin =====
The expected and correct output is:
B: Handling call with 1 args
B: Handling call one
B: Handling call with 1 args
B: Handling call with 3 args
B: Handling call three
B: Handling call with 3 args
B: Handling call with 2 args
B: Handling call two
B: Handling call with 2 args

The incorrect output is:
B: Handling call with 1 args
B: Handling call (null)
B: Handling call with 0 args
B: Handling call with 3 args
B: Handling call (null)
B: Handling call with 0 args
B: Handling call with 2 args
B: Handling call (null)
B: Handling call with 0 args

The issue can be tracked down to the generated assembly code where the code
puts a static zero on the stack for printf (instead of the address of the
char array), resulting in the "(null)" output. Same goes for the "0 args"
output.

The incorrect assembly code can be found in lines 30-35 of the attached s file:
movl $0, 4(%esp)
movl $LC1, (%esp)
call _printf
movl $0, 4(%esp)
movl $LC0, (%esp)
call _printf
===== quote end =====

I'll attach the test program and additional files. Please note that I had to
make slightly modifications to the section names and linker options in order
to get gcc 4.6.3-1 (or its ld) to sort the sections in alphabetic order
(compared to the test program that I filed with the TDM-GCC bug).

thank you for looking into this issue,
Chris


-- System Information:
Debian Release: wheezy/sid
  APT prefers testing
  APT policy: (500, 'testing')
Architecture: amd64 (x86_64)

Kernel: Linux 3.2.0-2-amd64 (SMP w/2 CPU cores)
Locale: LANG=en_CA.utf8, LC_CTYPE=en_CA.utf8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash

Versions of packages gcc-4.6 depends on:
ii  binutils      2.22-6.1
ii  cpp-4.6       4.6.3-1
ii  gcc-4.6-base  4.6.3-1
ii  libc6         2.13-32
ii  libgcc1       1:4.7.0-8
ii  libgmp10      2:5.0.5+dfsg-1.1
ii  libgomp1      4.7.0-8
ii  libmpc2       0.9-4
ii  libmpfr4      3.1.0-5
ii  libquadmath0  4.7.0-8
ii  zlib1g        1:1.2.7.dfsg-11

Versions of packages gcc-4.6 recommends:
ii  libc6-dev  2.13-32

Versions of packages gcc-4.6 suggests:
pn  binutils-gold        <none>
pn  gcc-4.6-doc          <none>
pn  gcc-4.6-locales      <none>
pn  gcc-4.6-multilib     4.6.3-1
pn  libgcc1-dbg          <none>
pn  libgomp1-dbg         <none>
pn  libmudflap0-4.6-dev  <none>
pn  libmudflap0-dbg      <none>
pn  libquadmath0-dbg     <none>

-- no debconf information
/* This program reveals a bug in:
 *  - TDM-GCC 4.6.1 (tdm64-1)
 *  - MinGW gcc 4.6.2 (GCC)
 *  - Debian Wheezy amd64 gcc 4.6.3 (Debian 4.6.3-1)
 * in three optimization levels for 32 bit.
 * 64 bit is not affected. In detail:
 *
 * The function "broken" shows results of the incorrect code.
 * The function "working" works on all optimization levels and
 * bitnesses.
 * The only difference between those functions is that "broken" uses
 * a local variable for array access while "working" uses a global one.
 *
 * broken:
 *   gcc -m32 -Wall -Werror -O1 -Wl,--sort-section=name -o tdmbug tdmbug.c
 *   gcc -m32 -Wall -Werror -O2 -Wl,--sort-section=name -o tdmbug tdmbug.c
 *   gcc -m32 -Wall -Werror -O3 -Wl,--sort-section=name -o tdmbug tdmbug.c
 *
 * working:
 *   gcc -m32 -Wall -Werror -O0 -Wl,--sort-section=name -o tdmbug tdmbug.c
 *   gcc -m64 -Wall -Werror -O0 -Wl,--sort-section=name -o tdmbug tdmbug.c
 *   gcc -m64 -Wall -Werror -O1 -Wl,--sort-section=name -o tdmbug tdmbug.c
 *   gcc -m64 -Wall -Werror -O2 -Wl,--sort-section=name -o tdmbug tdmbug.c
 *   gcc -m64 -Wall -Werror -O3 -Wl,--sort-section=name -o tdmbug tdmbug.c
 */

#include <stdio.h>

__attribute__((section(".rodata.SysWrap_nargs_aaa")))
   const int na_aaa = 0;
__attribute__((section(".rodata.SysWrap_nargs_one")))
   const int na_one = 1;
__attribute__((section(".rodata.SysWrap_nargs_two")))
   const int na_two = 2;
__attribute__((section(".rodata.SysWrap_nargs_three")))
   const int na_three = 3;
__attribute__((section(".rodata.SysWrap_nargs_zzz")))
   const int na_zzz = 0;

__attribute__((section(".rodata.SysWrap_before_names_aaa")))
   const char *const bn_aaa = NULL;
__attribute__((section(".rodata.SysWrap_before_names_one")))
   const char *const bn_one = "one";
__attribute__((section(".rodata.SysWrap_before_names_two")))
   const char *const bn_two = "two";
__attribute__((section(".rodata.SysWrap_before_names_three")))
   const char *const bn_three = "three";
__attribute__((section(".rodata.SysWrap_before_names_zzz")))
   const char *const bn_zzz = NULL;

int g_num_names;

void broken(void)
{
	const char * const * names;
	int i;

	g_num_names = 0;
	for (i = 0, names = &bn_aaa + 1; names < &bn_zzz; i++, names++) {
		g_num_names++;
		printf("B: Handling call with %d args\n", *(&na_aaa + 1 + i));
		printf("B: Handling call %s\n", *names);
		printf("B: Handling call with %d args\n", *(&na_aaa + 1 + i));
	}
}

void working(void)
{
	const char * const * names;
	int i;

	g_num_names = 0;
	for (i = 0, names = &bn_aaa + 1; names < &bn_zzz; i++, names++) {
		g_num_names++;
		printf("W: Handling call with %d args\n", *(&na_aaa + g_num_names));
		printf("W: Handling call %s\n", *names);
		printf("W: Handling call with %d args\n", *(&na_aaa + g_num_names));
	}
}

int main(void)
{
	working();
	broken();
	
	return 0;
}
	.file	"tdmbug.c"
	.section	.rodata.str1.4,"aMS",@progbits,1
	.align 4
..LC0:
	.string	"B: Handling call with %d args\n"
	.section	.rodata.str1.1,"aMS",@progbits,1
..LC1:
	.string	"B: Handling call %s\n"
	.text
	.globl	broken
	.type	broken, @function
broken:
..LFB11:
	.cfi_startproc
	pushl	%esi
	.cfi_def_cfa_offset 8
	.cfi_offset 6, -8
	pushl	%ebx
	.cfi_def_cfa_offset 12
	.cfi_offset 3, -12
	subl	$20, %esp
	.cfi_def_cfa_offset 32
	movl	$0, g_num_names
	movl	$bn_aaa+4, %eax
	cmpl	$bn_zzz, %eax
	jae	.L1
	movl	$bn_zzz+3, %esi
	subl	$bn_aaa+8, %esi
	shrl	$2, %esi
	addl	$1, %esi
	movl	$0, %ebx
..L3:
	addl	$1, g_num_names
	movl	na_aaa+4(,%ebx,4), %eax
	movl	%eax, 4(%esp)
	movl	$.LC0, (%esp)
	call	printf
	movl	$0, 4(%esp)
	movl	$.LC1, (%esp)
	call	printf
	movl	$0, 4(%esp)
	movl	$.LC0, (%esp)
	call	printf
	addl	$1, %ebx
	cmpl	%esi, %ebx
	jne	.L3
..L1:
	addl	$20, %esp
	.cfi_def_cfa_offset 12
	popl	%ebx
	.cfi_def_cfa_offset 8
	.cfi_restore 3
	popl	%esi
	.cfi_def_cfa_offset 4
	.cfi_restore 6
	ret
	.cfi_endproc
..LFE11:
	.size	broken, .-broken
	.section	.rodata.str1.4
	.align 4
..LC2:
	.string	"W: Handling call with %d args\n"
	.section	.rodata.str1.1
..LC3:
	.string	"W: Handling call %s\n"
	.text
	.globl	working
	.type	working, @function
working:
..LFB12:
	.cfi_startproc
	pushl	%ebx
	.cfi_def_cfa_offset 8
	.cfi_offset 3, -8
	subl	$24, %esp
	.cfi_def_cfa_offset 32
	movl	$0, g_num_names
	movl	$bn_aaa+4, %eax
	cmpl	$bn_zzz, %eax
	jae	.L5
	movl	%eax, %ebx
..L7:
	movl	g_num_names, %eax
	addl	$1, %eax
	movl	%eax, g_num_names
	movl	na_aaa(,%eax,4), %eax
	movl	%eax, 4(%esp)
	movl	$.LC2, (%esp)
	call	printf
	movl	(%ebx), %eax
	movl	%eax, 4(%esp)
	movl	$.LC3, (%esp)
	call	printf
	movl	g_num_names, %eax
	movl	na_aaa(,%eax,4), %eax
	movl	%eax, 4(%esp)
	movl	$.LC2, (%esp)
	call	printf
	addl	$4, %ebx
	cmpl	$bn_zzz, %ebx
	jb	.L7
..L5:
	addl	$24, %esp
	.cfi_def_cfa_offset 8
	popl	%ebx
	.cfi_def_cfa_offset 4
	.cfi_restore 3
	ret
	.cfi_endproc
..LFE12:
	.size	working, .-working
	.globl	main
	.type	main, @function
main:
..LFB13:
	.cfi_startproc
	pushl	%ebp
	.cfi_def_cfa_offset 8
	.cfi_offset 5, -8
	movl	%esp, %ebp
	.cfi_def_cfa_register 5
	andl	$-16, %esp
	call	working
	call	broken
	movl	$0, %eax
	leave
	.cfi_restore 5
	.cfi_def_cfa 4, 4
	ret
	.cfi_endproc
..LFE13:
	.size	main, .-main
	.comm	g_num_names,4,4
	.globl	bn_zzz
	.section	.rodata.SysWrap_before_names_zzz,"a",@progbits
	.align 4
	.type	bn_zzz, @object
	.size	bn_zzz, 4
bn_zzz:
	.zero	4
	.globl	bn_three
	.section	.rodata.str1.1
..LC4:
	.string	"three"
	.section	.rodata.SysWrap_before_names_three,"a",@progbits
	.align 4
	.type	bn_three, @object
	.size	bn_three, 4
bn_three:
	.long	.LC4
	.globl	bn_two
	.section	.rodata.str1.1
..LC5:
	.string	"two"
	.section	.rodata.SysWrap_before_names_two,"a",@progbits
	.align 4
	.type	bn_two, @object
	.size	bn_two, 4
bn_two:
	.long	.LC5
	.globl	bn_one
	.section	.rodata.str1.1
..LC6:
	.string	"one"
	.section	.rodata.SysWrap_before_names_one,"a",@progbits
	.align 4
	.type	bn_one, @object
	.size	bn_one, 4
bn_one:
	.long	.LC6
	.globl	bn_aaa
	.section	.rodata.SysWrap_before_names_aaa,"a",@progbits
	.align 4
	.type	bn_aaa, @object
	.size	bn_aaa, 4
bn_aaa:
	.zero	4
	.globl	na_zzz
	.section	.rodata.SysWrap_nargs_zzz,"a",@progbits
	.align 4
	.type	na_zzz, @object
	.size	na_zzz, 4
na_zzz:
	.zero	4
	.globl	na_three
	.section	.rodata.SysWrap_nargs_three,"a",@progbits
	.align 4
	.type	na_three, @object
	.size	na_three, 4
na_three:
	.long	3
	.globl	na_two
	.section	.rodata.SysWrap_nargs_two,"a",@progbits
	.align 4
	.type	na_two, @object
	.size	na_two, 4
na_two:
	.long	2
	.globl	na_one
	.section	.rodata.SysWrap_nargs_one,"a",@progbits
	.align 4
	.type	na_one, @object
	.size	na_one, 4
na_one:
	.long	1
	.globl	na_aaa
	.section	.rodata.SysWrap_nargs_aaa,"a",@progbits
	.align 4
	.type	na_aaa, @object
	.size	na_aaa, 4
na_aaa:
	.zero	4
	.ident	"GCC: (Debian 4.6.3-1) 4.6.3"
	.section	.note.GNU-stack,"",@progbits

Reply to: