diff options
author | Bernd Schmidt <bernds@codesourcery.com> | 2011-04-11 13:13:18 +0200 |
---|---|---|
committer | Bernd Schmidt <bernds@codesourcery.com> | 2011-04-11 13:26:48 +0200 |
commit | 56ea76b6bf190bffdc07aba90e4b25dfc096027b (patch) | |
tree | 8644959d652ecf68e190f0652cff04f44e88f715 /ldso/ldso/c6x | |
parent | 85f4b028d767fc390a7b866d2f58d58be489242d (diff) |
Fix nommu handling of DT_TEXTREL
We have a problem with DT_TEXTREL shared libraries on nommu machines.
The dynamic linker's strategy is to map the text segment read-only
first, then look for DT_TEXTREL, and use mprotect to change protections
if necessary. This fails on nommu, since a nommu kernel can decide to
share the memory for private read-only file mappings, and mprotect
doesn't (can't) do anything about this sharing. Existing nommu targets
apparently have no need for this, but on C6X, we may need to assign
library indices at run-time if no --dsbt-index option was passed to the
linker at build time.
Hence, the following patch, which instead of using mprotect, redoes the
mapping with PF_W set.
Signed-off-by: Bernd Schmidt <bernds@codesourcery.com>
Diffstat (limited to 'ldso/ldso/c6x')
-rw-r--r-- | ldso/ldso/c6x/dl-inlines.h | 29 | ||||
-rw-r--r-- | ldso/ldso/c6x/dl-sysdep.h | 3 |
2 files changed, 32 insertions, 0 deletions
diff --git a/ldso/ldso/c6x/dl-inlines.h b/ldso/ldso/c6x/dl-inlines.h index d8fb42c55..62e1cc9ca 100644 --- a/ldso/ldso/c6x/dl-inlines.h +++ b/ldso/ldso/c6x/dl-inlines.h @@ -74,6 +74,35 @@ __dl_init_loadaddr_hdr (struct elf32_dsbt_loadaddr loadaddr, void *addr, #endif } +/* Replace an existing entry in the load map. */ +static __always_inline void +__dl_update_loadaddr_hdr (struct elf32_dsbt_loadaddr loadaddr, void *addr, + Elf32_Phdr *phdr) +{ + struct elf32_dsbt_loadseg *segdata; + void *oldaddr; + int i; + + for (i = 0; i < loadaddr.map->nsegs; i++) + if (loadaddr.map->segs[i].p_vaddr == phdr->p_vaddr + && loadaddr.map->segs[i].p_memsz == phdr->p_memsz) + break; + if (i == loadaddr.map->nsegs) + _dl_exit (-1); + + segdata = loadaddr.map->segs + i; + oldaddr = (void *)segdata->addr; + _dl_munmap (oldaddr, segdata->p_memsz); + segdata->addr = (Elf32_Addr) addr; + +#if defined (__SUPPORT_LD_DEBUG__) + if (_dl_debug) + _dl_dprintf(_dl_debug_file, "%i: changed mapping %x at %x (old %x), size %x\n", + loadaddr.map->nsegs-1, + segdata->p_vaddr, segdata->addr, oldaddr, segdata->p_memsz); +#endif +} + static __always_inline void __dl_loadaddr_unmap (struct elf32_dsbt_loadaddr loadaddr) { diff --git a/ldso/ldso/c6x/dl-sysdep.h b/ldso/ldso/c6x/dl-sysdep.h index 8f1b122d3..ff7accdf1 100644 --- a/ldso/ldso/c6x/dl-sysdep.h +++ b/ldso/ldso/c6x/dl-sysdep.h @@ -104,6 +104,9 @@ struct elf32_dsbt_loadaddr; (__dl_init_loadaddr_hdr ((LOADADDR), (ADDR), (PHDR), \ dl_init_loadaddr_load_count)) +#define DL_UPDATE_LOADADDR_HDR(LOADADDR, ADDR, PHDR) \ + (__dl_update_loadaddr_hdr ((LOADADDR), (ADDR), (PHDR))) + #define DL_LOADADDR_UNMAP(LOADADDR, LEN) \ (__dl_loadaddr_unmap ((LOADADDR))) |