This is the mail archive of the
binutils@sourceware.cygnus.com
mailing list for the binutils project.
Re: Bug (?) in initialization code.
- To: lucier at math dot purdue dot edu (Brad Lucier)
- Subject: Re: Bug (?) in initialization code.
- From: Brad Lucier <lucier at math dot purdue dot edu>
- Date: Mon, 20 Mar 2000 22:22:11 -0500 (EST)
- Cc: binutils at sourceware dot cygnus dot com, gcc-bugs at gcc dot gnu dot org, lucier at math dot purdue dot edu (Brad Lucier), feeley at iro dot umontreal dot ca
The code that needs to be changed to fix this seems to begin at line
4104 of varasm.c; see the analysis below. But I don't know how to fix it.
Ivan Kokshaysky was kind enough to point me to the REFLONG relocations
in the loader, which does what I want, loads the lower 32 bits of a pointer
at load time; see elf64_alpha_howto_table in bfd/elf64-alpha.c in the
binutils source.
Compiling the following program actually bombs at line 5847 in c-typeck.c:
else if (require_constant_elements
&& initializer_constant_valid_p (value, TREE_TYPE (value)) == 0)
{
error_init ("initializer element is not computable at load time");
value = error_mark_node;
}
TREE_TYPE(value) is a union type, but the most likely candidate for the
type seems to be:
common = {
chain = 0x0,
type = 0x0,
code = INTEGER_TYPE,
side_effects_flag = 0,
constant_flag = 0,
permanent_flag = 0,
addressable_flag = 0,
volatile_flag = 0,
readonly_flag = 0,
unsigned_flag = 0,
asm_written_flag = 0,
used_flag = 0,
nothrow_flag = 0,
static_flag = 0,
public_flag = 0,
private_flag = 0,
protected_flag = 0,
lang_flag_0 = 0,
lang_flag_1 = 0,
lang_flag_2 = 0,
lang_flag_3 = 0,
lang_flag_4 = 0,
lang_flag_5 = 0,
lang_flag_6 = 0
},
It seems that value is a pointer to the following union element:
common = {
chain = 0x0,
type = 0x2000002a700,
code = NOP_EXPR,
side_effects_flag = 2,
constant_flag = 2,
permanent_flag = 2,
addressable_flag = 2,
volatile_flag = 2,
readonly_flag = 2,
unsigned_flag = 2,
asm_written_flag = 2,
used_flag = 0,
nothrow_flag = 0,
static_flag = 0,
public_flag = 0,
private_flag = 0,
protected_flag = 0,
lang_flag_0 = 0,
lang_flag_1 = 0,
lang_flag_2 = 0,
lang_flag_3 = 0,
lang_flag_4 = 0,
lang_flag_5 = 0,
lang_flag_6 = 0
},
and the code in varasm.c that handles this case seems to begin at line
4072:
case CONVERT_EXPR:
case NOP_EXPR:
/* Allow conversions between pointer types. */
if (POINTER_TYPE_P (TREE_TYPE (value))
&& POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
/* Allow conversions between real types. */
if (FLOAT_TYPE_P (TREE_TYPE (value))
&& FLOAT_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
/* Allow length-preserving conversions between integer types. */
if (INTEGRAL_TYPE_P (TREE_TYPE (value))
&& INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0)))
&& (TYPE_PRECISION (TREE_TYPE (value))
== TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0)))))
return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
/* Allow conversions between other integer types only if
explicit value. */
if (INTEGRAL_TYPE_P (TREE_TYPE (value))
&& INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
{
tree inner = initializer_constant_valid_p (TREE_OPERAND (value, 0),
endtype);
if (inner == null_pointer_node)
return null_pointer_node;
break;
}
/* Allow (int) &foo provided int is as wide as a pointer. */
if (INTEGRAL_TYPE_P (TREE_TYPE (value))
&& POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0)))
&& (TYPE_PRECISION (TREE_TYPE (value))
>= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0)))))
return initializer_constant_valid_p (TREE_OPERAND (value, 0),
endtype);
/* Likewise conversions from int to pointers, but also allow
conversions from 0. */
if (POINTER_TYPE_P (TREE_TYPE (value))
&& INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
{
if (integer_zerop (TREE_OPERAND (value, 0)))
return null_pointer_node;
else if (TYPE_PRECISION (TREE_TYPE (value))
<= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0))))
return initializer_constant_valid_p (TREE_OPERAND (value, 0),
endtype);
}
/* Allow conversions to union types if the value inside is okay. */
if (TREE_CODE (TREE_TYPE (value)) == UNION_TYPE)
return initializer_constant_valid_p (TREE_OPERAND (value, 0),
endtype);
break;
So it seems that we should allow (int) &foo for alpha.c even though
int is 32 bits and a pointer is 64, if I will use the -taso switch
with ld (which Kokshaysky says is OK). Also for conversion from
int->pointers.
Brad Lucier
>
> The following program:
>
> /* compile with gcc -c foo.c on alpha */
>
> typedef int int32;
> typedef long int64;
>
> typedef struct { int a; int b; } foo;
>
> extern foo f;
>
> static int32 tbl1[] =
> {
> (int32) &f
> };
>
> static int64 tbl2[] =
> {
> (int64) &f
> };
>
> static foo* tbl3[] =
> {
> &f
> };
>
> compiled on alphaev6 with any gcc version I tried from 2.95.1 on
> bombs and gives the following error message:
>
> foo.c:13: initializer element is not computable at load time
> foo.c:13: (near initialization for `tbl1[0]')
>
> The problem seems to be that gcc thinks the loader cannot stuff
> a 64bit pointer into a 32bit int at load time.
>
> I intend to use the -taso flag with ld 2.9.5.0.27 (H. J. Lu's release).
>
> So, the questions:
>
> 1. Can the loader handle this construct correctly, given the -taso flag?
> 2. Should gcc allow this construct?