Subject: Re: mips gcc4 ld.elf_so problems
To: Simon Burge <simonb@NetBSD.org>
From: Jason Thorpe <thorpej@shagadelic.org>
List: tech-toolchain
Date: 06/27/2006 08:52:30
On Jun 27, 2006, at 8:50 AM, Jason Thorpe wrote:
>
> On Jun 27, 2006, at 6:02 AM, Simon Burge wrote:
>
>> ld.elf_so is having alignment issues with mips and gcc4 C++ programs.
>> The core of the problem is that we have a function store_ptr()
>> which is
>>
>> static inline void
>> store_ptr(void *where, Elf_Addr val)
>> {
>> memcpy(where, &val, sizeof(val));
>> }
>>
>> The idea of this is that we sometimes want to store a Elf_Addr
>> (uint32_t) at an unaligned address, so we use memcpy to write the
>> data.
>> This was added for gcc3 which started using aligned data for some GOT
>> info.
>
> I think if you do this:
>
> static inline void
> store_ptr(void *where, Elf_Addr val)
> {
> void *from = &val;
Oops, make that:
const void *from = &val;
:-)
>
> memcpy(where, from, sizeof(val));
> }
>
> that it will work. And that is a lot less invasive than your
> proposed change.
>
>
>>
>> The code that calls this does:
>>
>> Elf_Addr *where;
>>
>> where = ....
>> store_ptr(where, value);
>>
>> With gcc3 this generated code like:
>>
>> swl $2,3($8)
>> swr $2,0($8)
>>
>> and with gcc4 this generates:
>>
>> sw $2,0($9)
>>
>> That is, with gcc4 it's an aligned store instead of an unaligned
>> store.
>>
>> Just adding casts at various places didn't help, both at the caller
>> and inside store_ptr() didn't help. The patch below works around
>> this
>> by starting with a void * variable, which obviously doesn't have any
>> alignment constraints.
>>
>> Now, the question is "is what gcc4 is doing right?". Since we
>> started
>> with a pointer to Elf_Addr, is the optimiser legal in saying that
>> that
>> pointer is always aligned so it an optimise the store in to an
>> aligned
>> store? Or is it a bug with gcc4 and memcpy and assuming alignment?
>>
>> Cheers,
>> Simon.
>> --
>>
>> Index: libexec/ld.elf_so/arch/mips/mips_reloc.c
>> ===================================================================
>> RCS file: /cvsroot/src/libexec/ld.elf_so/arch/mips/mips_reloc.c,v
>> retrieving revision 1.51
>> diff -d -p -u -r1.51 mips_reloc.c
>> --- libexec/ld.elf_so/arch/mips/mips_reloc.c 3 Apr 2006 13:23:15
>> -0000 1.51
>> +++ libexec/ld.elf_so/arch/mips/mips_reloc.c 27 Jun 2006 05:20:55
>> -0000
>> @@ -86,6 +86,7 @@ _rtld_relocate_nonplt_self(Elf_Dyn *dynp
>> {
>> const Elf_Rel *rel = 0, *rellim;
>> Elf_Addr relsz = 0;
>> + void *wherev;
>> Elf_Addr *where;
>> const Elf_Sym *symtab = NULL, *sym;
>> Elf_Addr *got = NULL;
>> @@ -133,7 +134,8 @@ _rtld_relocate_nonplt_self(Elf_Dyn *dynp
>>
>> rellim = (const Elf_Rel *)((caddr_t)rel + relsz);
>> for (; rel < rellim; rel++) {
>> - where = (Elf_Addr *)(relocbase + rel->r_offset);
>> + wherev = (void *)(relocbase + rel->r_offset);
>> + where = wherev;
>>
>> switch (ELF_R_TYPE(rel->r_info)) {
>> case R_TYPE(NONE):
>> @@ -146,7 +148,7 @@ _rtld_relocate_nonplt_self(Elf_Dyn *dynp
>> if (__predict_true(RELOC_ALIGNED_P(where)))
>> *where += relocbase;
>> else
>> - store_ptr(where, load_ptr(where) + relocbase);
>> + store_ptr(wherev, load_ptr(wherev) + relocbase);
>> break;
>>
>> default:
>> @@ -246,9 +248,12 @@ _rtld_relocate_nonplt_objects(const Obj_
>> got = obj->pltgot;
>> for (rel = obj->rel; rel < obj->rellim; rel++) {
>> Elf_Addr *where, tmp;
>> + void *wherev;
>> unsigned long symnum;
>>
>> - where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
>> + /* store address in a non-alignment restricted pointer first */
>> + wherev = obj->relocbase + rel->r_offset;
>> + where = wherev;
>> symnum = ELF_R_SYM(rel->r_info);
>>
>> switch (ELF_R_TYPE(rel->r_info)) {
>> @@ -263,12 +268,12 @@ _rtld_relocate_nonplt_objects(const Obj_
>> if (__predict_true(RELOC_ALIGNED_P(where)))
>> tmp = *where;
>> else
>> - tmp = load_ptr(where);
>> + tmp = load_ptr(wherev);
>> tmp += got[obj->local_gotno + symnum - obj->gotsym];
>> if (__predict_true(RELOC_ALIGNED_P(where)))
>> *where = tmp;
>> else
>> - store_ptr(where, tmp);
>> + store_ptr(wherev, tmp);
>>
>> rdbg(("REL32/G %s in %s --> %p in %s",
>> obj->strtab + def->st_name, obj->path,
>> @@ -293,7 +298,7 @@ _rtld_relocate_nonplt_objects(const Obj_
>> if (__predict_true(RELOC_ALIGNED_P(where)))
>> tmp = *where;
>> else
>> - tmp = load_ptr(where);
>> + tmp = load_ptr(wherev);
>>
>> if (def->st_info ==
>> ELF_ST_INFO(STB_LOCAL, STT_SECTION)
>> @@ -307,7 +312,7 @@ _rtld_relocate_nonplt_objects(const Obj_
>> if (__predict_true(RELOC_ALIGNED_P(where)))
>> *where = tmp;
>> else
>> - store_ptr(where, tmp);
>> + store_ptr(wherev, tmp);
>>
>> rdbg(("REL32/L %s in %s --> %p in %s",
>> obj->strtab + def->st_name, obj->path,
>> @@ -319,7 +324,7 @@ _rtld_relocate_nonplt_objects(const Obj_
>> rdbg(("sym = %lu, type = %lu, offset = %p, "
>> "contents = %p, symbol = %s",
>> symnum, (u_long)ELF_R_TYPE(rel->r_info),
>> - (void *)rel->r_offset, (void *)load_ptr(where),
>> + (void *)rel->r_offset, (void *)load_ptr(wherev),
>> obj->strtab + obj->symtab[symnum].st_name));
>> _rtld_error("%s: Unsupported relocation type %ld "
>> "in non-PLT relocations\n",
>
> -- thorpej
-- thorpej