Subject: MIPS gas problem

From: Hiroyuki Machida <[email-masked]>
Date: Thu, 20 Apr 2000 11:13:20 +0900

Hi

I found the problem  "__attribute__ ((aligned(xx))" doesn't work
properly on MIPS/Linux. Please try to execute the attached test. 
I think this problem can be reproduced on any ELF/MIPS box except
EMBEDED system which has OS name "elf". 

I tracked down and finaly found gas/config/t-mips.c:s_change_sec(sec) 
sets  always ".rodata" section-alignment to 2**4. This should be set 
to the maximum rodata object's alignment value.

% cc -c  rotest.c -o rotest.o
% objdump -h rotest.o

rotest.o:     file format elf32-littlemips

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .text         00000330  0000000000000000  0000000000000000  00000040  2**4
                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
  1 .data         00000010  0000000000000000  0000000000000000  00000370  2**4
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000000  0000000000000000  0000000000000000  00000380  2**4
                  ALLOC
  3 .reginfo      00000018  0000000000000000  0000000000000000  00000380  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA,LINK_ONCE_SAME_SIZE
  4 .mdebug       000002f8  0000000000000000  0000000000000000  00000398  2**2
                  CONTENTS, READONLY, DEBUGGING
  5 .rodata       00002060  0000000000000000  0000000000000000  00000690  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, DATA

The sample fix for binutils 2.9.1 is following. (This can be
apply to current CVS version, I suppose.)

Does anyone know the reason why gas/config/t-mips.c set to "rodata'
section alignment to 2**4 and ignore the maximum rodata object
alignment.? We have to know why this restriction is made, anyway.

---
Hiroyuki Machida
Creative Station		SCE Inc./Sony Corp.

Index: tc-mips.c
===================================================================
RCS file: /usr/cvsroot/caesar/src/compiler/binutils/gas/config/tc-mips.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -U10 -p -r1.4 -r1.5
--- tc-mips.c	1999/07/07 01:03:55	1.4
+++ tc-mips.c	2000/04/12 06:50:19	1.5
@@ -9727,21 +9727,28 @@ s_change_sec (sec)
 			    (subsegT) get_absolute_expression ());
 	  if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
 	    {
 	      bfd_set_section_flags (stdoutput, seg,
 				     (SEC_ALLOC
 				      | SEC_LOAD
 				      | SEC_READONLY
 				      | SEC_RELOC
 				      | SEC_DATA));
 	      if (strcmp (TARGET_OS, "elf") != 0)
-		bfd_set_section_alignment (stdoutput, seg, 4);
+	        {
+		  static char first = 1;
+		  if (first)
+		    {
+		      bfd_set_section_alignment (stdoutput, seg, 4);
+		      first=0;
+		    }
+	        }
 	    }
 	  demand_empty_rest_of_line ();
 	}
       else
 	{
 	  as_bad ("No read only data section in this object file format");
 	  demand_empty_rest_of_line ();
 	  return;
 	}
       break;
@@ -9749,21 +9756,28 @@ s_change_sec (sec)
     case 's':
       if (USE_GLOBAL_POINTER_OPT)
 	{
 	  seg = subseg_new (".sdata", (subsegT) get_absolute_expression ());
 	  if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
 	    {
 	      bfd_set_section_flags (stdoutput, seg,
 				     SEC_ALLOC | SEC_LOAD | SEC_RELOC
 				     | SEC_DATA);
 	      if (strcmp (TARGET_OS, "elf") != 0)
-		bfd_set_section_alignment (stdoutput, seg, 4);
+	        {
+		  static char first = 1;
+		  if (first)
+		    {
+		      bfd_set_section_alignment (stdoutput, seg, 4);
+		      first=0;
+		    }
+	        }
 	    }
 	  demand_empty_rest_of_line ();
 	  break;
 	}
       else
 	{
 	  as_bad ("Global pointers not supported; recompile -G 0");
 	  demand_empty_rest_of_line ();
 	  return;
 	}

--- end of patch

/*
 * rotest.c - rodata alignment test.
 */

#define AL1 1024
#define AL2 4096
const char globalc='a';
const int global1 __attribute__ ((aligned(AL1))) =0 ;
const int global2 __attribute__ ((aligned(AL2))) =1;

const int local1 __attribute__ ((aligned(AL1))) =0 ;
const int local2 __attribute__ ((aligned(AL2))) =1;

int total_ng=0;

void check(char *addr, unsigned long al)
{
        unsigned long mask = (al -1);
        if ((unsigned long) addr & mask){
                total_ng ++;
                printf("err:%x expected:%x\n", addr, 
				(unsigned long) addr & ~mask);
        }
}

int
main(void)
{
        printf("* readonly local/gloabl\n");
        printf("chcking align:%x\n",AL1);
        check((char *)&local1,AL1); check((char *)&global1,AL1);
        printf("%x:%x\n", &local1,&global1);
        printf("chcking align:%x\n",4096);
        check((char *)&global1,AL2); check((char *)&global2,AL2);
        printf("%x:%x\n", &global1,&global2);

        printf("\n");
        if (total_ng) {
                printf("NG:%d\n",total_ng);
        } else {
                printf("OK\n");
        }
        printf("\n");
        return total_ng;
}

--- end of test

---

From: Florian Lohoff <[email-masked]>
Date: Thu, 20 Apr 2000 12:16:10 +0200

> to the maximum rodata object's alignment value.

Hmm,
if i understand that correctly i am seeing a different behaviour:
(egcs 1.0.3a + binutils 2.8.1)

[flo@repeat flo]$ gcc -save-temps -o rotest rotest.c
rotest.c:8: warning: alignment of `global1' is greater than maximum object file alignment
rotest.c:9: warning: alignment of `global2' is greater than maximum object file alignment
rotest.c:11: warning: alignment of `local1' is greater than maximum object file alignment
rotest.c:12: warning: alignment of `local2' is greater than maximum object file alignment

And i see only a max alignment 3 in the rotest.s, and as expected
the test fails:

[flo@repeat flo]$ ./rotest 
* readonly local/gloabl
chcking align:400
err:4007a8 expected:400400
err:400798 expected:400400
4007a8:400798
chcking align:1000
err:400798 expected:400000
err:4007a0 expected:400000
400798:4007a0

NG:4

Flo
-- 
Florian Lohoff		[email-masked]		      	+49-subject-2-change
"Technology is a constant battle between manufacturers producing bigger and
more idiot-proof systems and nature producing bigger and better idiots."

---

From: "Koundinya.K" <[email-masked]>
Date: Thu, 20 Apr 2000 17:37:56 +0530

[email-masked] said:
-> Hi
-> I found the problem  "__attribute__ ((aligned(xx))" doesn't work
-> properly on MIPS/Linux. Please try to execute the attached test.  I
-> think this problem can be reproduced on any ELF/MIPS box except
-> EMBEDED system which has OS name "elf". 

-> I tracked down and finaly found gas/config/t-mips.c:s_change_sec(sec)
-> sets  always ".rodata" section-alignment to 2**4. This should be set
-> to the maximum rodata object's alignment value.

I am seeing something different (gcc 2.95.2 and binutils from snapshot 
000213) on my mips based machine (mips-dde-sysv4.2MP)

[~] gcc -c  rotest.c -o rotest.o
rotest.c:8: warning: alignment of `global1' is greater than maximum object 
file alignment. Using 8.
rotest.c:9: warning: alignment of `global2' is greater than maximum object 
file alignment. Using 8.
rotest.c:11: warning: alignment of `local1' is greater than maximum object 
file alignment. Using 8.
rotest.c:12: warning: alignment of `local2' is greater than maximum object 
file alignment. Using 8.

koundinya

---

From: Hiroyuki Machida <[email-masked]>
Date: Fri, 21 Apr 2000 10:52:25 +0900

I rewrite the test program which is not depending your gcc version
or config. Please try this.

#define P1  10
#define P2  12
#define P1STR  "10"
#define P2STR  "12"
#define AL1 (2<<(P1-1))
#define AL2 (2<<(P2-1))

asm( 
"	.globl	globalc;\n"
"	.rdata;\n"
"	.type	 globalc,@object;\n"
"	.size	 globalc,1;\n"
"globalc:\n"
"	.byte	97;\n"
);

asm( 
"	.globl	global1;\n"
"	.align	" P1STR ";\n"
"	.type	 global1,@object;\n"
"	.size	 global1,4;\n"
"global1:\n"
"	.word	0;\n"
);

asm( 
"	.globl	global2;\n"
"	.align	" P2STR ";\n"
"	.type	 global2,@object;\n"
"	.size	 global2,4;\n"
"global2:\n"
"	.word	1;\n"
);

int total_ng=0;

int
main(void)
{
	extern int global1, global2;
	extern char globalc;

        printf("* readonly gloabl\n");
        printf("chcking align:%x\n",AL1);
        check((char *)&global1,AL1); 
        printf("%x\n", &global1);

        printf("chcking align:%x\n",AL2);
        check((char *)&global2,AL2); 
        printf("%x\n", &global2);

        printf("\n");
        if (total_ng) {

}

---

From: Hiroyuki Machida <[email-masked]>
Date: Fri, 21 Apr 2000 12:30:14 +0900

Hi Ian,

From: Ian Lance Taylor <[email-masked]>
Subject: Re: MIPS gas problem
Date: 20 Apr 2000 09:48:12 -0700

>    rotest.c:8: warning: alignment of `global1' is greater than maximum object 

This message is a gcc issue, as you said. 

But, my reported plobelm is really binutils issue. Sorry to confuse
you. I will describe the problem using only asm file, again. 

Assmbling and linking attached al.S, I got the following result.

% cc -o al -save-temps al.S

% nm al.o | grep global
0000000000000400 R global1
0000000000001000 R global2
0000000000000000 R globalc

% nm al | grep global
0000000000400dc0 R global1
00000000004019c0 R global2
00000000004009c0 R globalc

Alignments of global1 and global2  in "al.o" looks good. But in "al" 
not.

% objdump -h al.o | grep rodata
  5 .rodata       00001010  0000000000000000  0000000000000000 00000250  2**4

% objdump -h al | grep rodata
  9 .rodata       00001010  00000000004009c0  00000000004009c0 000009c0  2**4

I think when ld gathers read only section, the alignment will be broken.
Because .rodata section alignment of al.o is not the maximum rodata
object's alignment value(in this case 2**12).

I tracked down and found that s_change_sec():gas/config/tc-mips.c
resets section alignment to 2**4. 
So, the maximum rodata object's alignment value will be lost in the
following sequence. 

	.rdata		// reset  section-alignment to 2**4
	.algin	10	// update section-alignment to 2**10
        .type    global1,@object;
        .size    global1,4;
global1:
        .word   0;

	.rdata		// reset  section-alignment to 2**4, Why??
	.align	2	// not update ( 2 <= current section-alignment)
string:
        .ascii  "test\n"

I want to know the reason why s_change_sec() always reset
section-alignment to 2**4. I think this is wrong.

--- al.S
        .abicalls

        .globl  globalc;
        .rdata;
        .type    globalc,@object;
        .size    globalc,1;
globalc:
        .byte   97;

// rodata aligned 10 (1024)
        .globl  global1;
        .align  10;
        .type    global1,@object;
        .size    global1,4;
global1:
        .word   0;

// rodata aligned 12 (4096)
        .globl  global2;
        .align  12;
        .type    global2,@object;
        .size    global2,4;
global2:
        .word   1;

// data
        .globl  total_ng
        .data
        .align  2
        .type    total_ng,@object
        .size    total_ng,4
total_ng:
        .word   0

// rodata again
        .rdata
        .align  2
string:
        .ascii  "test\n"
        .text
        .align  3
        .globl  main
        .ent    main
main:
        nop;
        nop
        nop
        .end main
--- endof al.S

---
Hiroyuki Machida

---

From: Hiroyuki Machida <[email-masked]>
Date: Mon, 24 Apr 2000 12:16:51 +0900

Thank you Ian and Alan.

From: Ian Lance Taylor <[email-masked]>
Subject: Re: MIPS gas problem
Date: 21 Apr 2000 08:48:59 -0700

>    Date: Fri, 21 Apr 2000 12:30:14 +0900
>    From: Hiroyuki Machida <[email-masked]>
> 
>    But, my reported plobelm is really binutils issue.
> 
> I know.  I didn't mean to imply otherwise.  Alan Modra's suggested
> patch was the right one.
> 
> Ian

I summarize the problem and attach patch. Please install it, if you
can. I don't know what procedure is required to install the patch to
CVS tree. 

*Problem Description:
Current tc-mips.c:s_change_sec() always sets '.rdata' and '.sdata'
section alignments to 2**4, even if those contain over 2**4 aligned 
objects.

*Solution:
Tc-mips.c:s_change_sec() should use record_alignment(), not
bfd_set_section_alignment(), for preventing  reset section
alignments.

*Patch:

2000-04-24	Machida Hiroyuki <[email-masked]>

tc-mips.c (s_change_sec): Use record_alignment(), not 
  bfd_set_section_alignment() to preserve section aligenments. 

--- tc-mips.c.ORG	Mon Apr 24 11:22:39 2000
+++ tc-mips.c	Mon Apr 24 11:24:48 2000
@@ -10045,7 +10045,7 @@ s_change_sec (sec)
 				      | SEC_RELOC
 				      | SEC_DATA));
 	      if (strcmp (TARGET_OS, "elf") != 0)
-		bfd_set_section_alignment (stdoutput, seg, 4);
+		record_alignment (stdoutput, seg, 4);
 	    }
 	  demand_empty_rest_of_line ();
 	}
@@ -10067,7 +10067,7 @@ s_change_sec (sec)
 				     SEC_ALLOC | SEC_LOAD | SEC_RELOC
 				     | SEC_DATA);
 	      if (strcmp (TARGET_OS, "elf") != 0)
-		bfd_set_section_alignment (stdoutput, seg, 4);
+		record_alignment (stdoutput, seg, 4);
 	    }
 	  demand_empty_rest_of_line ();
 	  break;

---

From: "Koundinya.K" <[email-masked]>
Date: Mon, 24 Apr 2000 10:36:37 +0530

Hi,
[email-masked] said:
-> I rewrite the test program which is not depending your gcc version or
-> config. Please try this.

-> #define P1  10 #define P2  12

Sorry for the delay in trying out this test case. I was over the edge for 
the past 3 days :-)

O.K, There were no warnings with this test case unlike the previous one.

[~] gcc -c rotest1.c -o rotest1.o

[~] objdump -h objtest1.o

otest1.o:     file format elf32-tradbigmips

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         00000320  00000000  00000000  00000040  2**4
                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
  1 .data         00000010  00000000  00000000  00000360  2**4
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000000  00000000  00000000  00000370  2**4
                  ALLOC
  3 .reginfo      00000018  00000000  00000000  00000370  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA, LINK_ONCE_SAME_SIZE
  4 .mdebug       00000240  00000000  00000000  00000388  2**2
                  CONTENTS, READONLY, DEBUGGING
  5 .note         00000014  00000000  00000000  000005c8  2**0
                  CONTENTS, READONLY
  6 .comment      00000035  00000000  00000000  000005dc  2**0
                  CONTENTS, READONLY
  7 .rodata       00001060  00000000  00000000  00000620  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, DATA

koundinya