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:50:14
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;
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