Fix read/write of existing file using mmap and different layout of the ELF

file.
This commit is contained in:
Ulrich Drepper
2006-04-04 21:07:28 +00:00
parent dd7e22b4a0
commit 697d8d283e
4 changed files with 97 additions and 42 deletions
+13
View File
@@ -1,3 +1,16 @@
2006-04-04 Ulrich Drepper <drepper@redhat.com>
* elf32_updatefile.c (updatemmap): Cleanups. Remove shdr_dest
variable. Before writing sections, make a copy of the section
header data if necessary. Don't write section header while
writing the section constent, it might overwrite some sections.
Restore the pointer afterwards.
* elf32_updatenull.c (updatenull): If the offset of a section in a
file changed make sure we read the section so that it'll be written
out.
* elf_update.c: Remove debug message.
2005-12-07 Roland McGrath <roland@redhat.com>
* gelf_xlate.c [! ALLOW_UNALIGNED] (union unaligned): New type.
+70 -30
View File
@@ -1,5 +1,5 @@
/* Write changed data structures.
Copyright (C) 2000, 2001, 2002, 2004, 2005 Red Hat, Inc.
Copyright (C) 2000, 2001, 2002, 2004, 2005, 2006 Red Hat, Inc.
Written by Ulrich Drepper <drepper@redhat.com>, 2000.
This program is free software; you can redistribute it and/or modify
@@ -26,6 +26,7 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/param.h>
#include <system.h>
@@ -82,7 +83,6 @@ internal_function_def
__elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum)
{
ElfW2(LIBELFBITS,Ehdr) *ehdr;
xfct_t fctp;
char *last_position;
/* We need the ELF header several times. */
@@ -100,6 +100,7 @@ __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum)
{
/* Today there is only one version of the ELF header. */
#if EV_NUM != 2
xfct_t fctp;
fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR];
#else
# undef fctp
@@ -137,6 +138,7 @@ __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum)
{
/* Today there is only one version of the ELF header. */
#if EV_NUM != 2
xfct_t fctp;
fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR];
#else
# undef fctp
@@ -166,12 +168,11 @@ __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum)
/* Write all the sections. Well, only those which are modified. */
if (shnum > 0)
{
ElfW2(LIBELFBITS,Shdr) *shdr_dest;
Elf_ScnList *list = &elf->state.ELFW(elf,LIBELFBITS).scns;
Elf_Scn **scns = (Elf_Scn **) alloca (shnum * sizeof (Elf_Scn *));
char *shdr_start = ((char *) elf->map_address + elf->start_offset
+ ehdr->e_shoff);
char *shdr_end = shdr_start + ehdr->e_shnum * ehdr->e_shentsize;
char *const shdr_start = ((char *) elf->map_address + elf->start_offset
+ ehdr->e_shoff);
char *const shdr_end = shdr_start + ehdr->e_shnum * ehdr->e_shentsize;
#if EV_NUM != 2
xfct_t shdr_fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR];
@@ -179,26 +180,43 @@ __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum)
# undef shdr_fctp
# define shdr_fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR]
#endif
shdr_dest = (ElfW2(LIBELFBITS,Shdr) *)
((char *) elf->map_address + elf->start_offset + ehdr->e_shoff);
#define shdr_dest ((ElfW2(LIBELFBITS,Shdr) *) shdr_start)
/* Get all sections into the array and sort them. */
sort_sections (scns, list);
/* We possibly have to copy the section header data because moving
the sections might overwrite the data. */
for (size_t cnt = 0; cnt < shnum; ++cnt)
{
Elf_Scn *scn = scns[cnt];
if ((scn->shdr_flags & ELF_F_MALLOCED) == 0
&& scn->shdr.ELFW(e,LIBELFBITS) != &shdr_dest[scn->index])
{
assert ((char *) elf->map_address + elf->start_offset
< (char *) scn->shdr.ELFW(e,LIBELFBITS));
assert ((char *) scn->shdr.ELFW(e,LIBELFBITS)
< (char *) elf->map_address + elf->maximum_size);
void *p = alloca (sizeof (ElfW2(LIBELFBITS,Shdr)));
scn->shdr.ELFW(e,LIBELFBITS)
= memcpy (p, scn->shdr.ELFW(e,LIBELFBITS),
sizeof (ElfW2(LIBELFBITS,Shdr)));
}
}
/* Iterate over all the section in the order in which they
appear in the output file. */
for (size_t cnt = 0; cnt < shnum; ++cnt)
{
Elf_Scn *scn = scns[cnt];
ElfW2(LIBELFBITS,Shdr) *shdr;
char *scn_start;
Elf_Data_List *dl;
shdr = scn->shdr.ELFW(e,LIBELFBITS);
ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
scn_start = ((char *) elf->map_address
+ elf->start_offset + shdr->sh_offset);
dl = &scn->data_list;
char *scn_start = ((char *) elf->map_address
+ elf->start_offset + shdr->sh_offset);
Elf_Data_List *dl = &scn->data_list;
if (shdr->sh_type != SHT_NOBITS && scn->data_list_rear != NULL)
do
@@ -236,10 +254,11 @@ __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum)
if (unlikely (change_bo))
{
#if EV_NUM != 2
xfct_t fctp;
fctp = __elf_xfctstom[__libelf_version - 1][dl->data.d.d_version - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type];
#else
# undef fctp
fctp = __elf_xfctstom[0][0][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type];
# define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type]
#endif
/* Do the real work. */
@@ -265,7 +284,23 @@ __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum)
/* We have to trust the existing section header information. */
last_position += shdr->sh_size;
/* Write the section header table entry if necessary. */
scn->flags &= ~ELF_F_DIRTY;
}
/* Fill the gap between last section and section header table if
necessary. */
if ((elf->flags & ELF_F_DIRTY)
&& last_position < ((char *) elf->map_address + elf->start_offset
+ ehdr->e_shoff))
memset (last_position, __libelf_fill_byte,
(char *) elf->map_address + elf->start_offset + ehdr->e_shoff
- last_position);
/* Write the section header table entry if necessary. */
for (size_t cnt = 0; cnt < shnum; ++cnt)
{
Elf_Scn *scn = scns[cnt];
if ((scn->shdr_flags | elf->flags) & ELF_F_DIRTY)
{
if (unlikely (change_bo))
@@ -277,25 +312,28 @@ __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum)
scn->shdr.ELFW(e,LIBELFBITS),
sizeof (ElfW2(LIBELFBITS,Shdr)));
/* If we previously made a copy of the section header
entry we now have to adjust the pointer again so
point to new place in the mapping. */
if ((scn->shdr_flags & ELF_F_MALLOCED) == 0)
scn->shdr.ELFW(e,LIBELFBITS) = &shdr_dest[scn->index];
scn->shdr_flags &= ~ELF_F_DIRTY;
}
scn->flags &= ~ELF_F_DIRTY;
}
/* Fill the gap between last section and section header table if
necessary. */
if ((elf->flags & ELF_F_DIRTY)
&& last_position < ((char *) elf->map_address + elf->start_offset
+ ehdr->e_shoff))
memset (last_position, __libelf_fill_byte,
(char *) elf->map_address + elf->start_offset + ehdr->e_shoff
- last_position);
}
/* That was the last part. Clear the overall flag. */
elf->flags &= ~ELF_F_DIRTY;
/* Make sure the content hits the disk. */
char *msync_start = ((char *) elf->map_address
+ elf->start_offset / sysconf (_SC_PAGESIZE));
char *msync_end = ((char *) elf->map_address
+ elf->start_offset + ehdr->e_shoff
* ehdr->e_shentsize * shnum);
(void) msync (msync_start, msync_end - msync_start, MS_SYNC);
return 0;
}
@@ -349,7 +387,6 @@ __elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum)
{
char fillbuf[FILLBUFSIZE];
size_t filled = 0;
xfct_t fctp;
/* We need the ELF header several times. */
ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
@@ -369,6 +406,7 @@ __elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum)
{
/* Today there is only one version of the ELF header. */
#if EV_NUM != 2
xfct_t fctp;
fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR];
#else
# undef fctp
@@ -419,6 +457,7 @@ __elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum)
{
/* Today there is only one version of the ELF header. */
#if EV_NUM != 2
xfct_t fctp;
fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR];
#else
# undef fctp
@@ -525,10 +564,11 @@ __elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum)
if (unlikely (change_bo))
{
#if EV_NUM != 2
xfct_t fctp;
fctp = __elf_xfctstom[__libelf_version - 1][dl->data.d.d_version - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type];
#else
# undef fctp
fctp = __elf_xfctstom[0][0][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type];
# define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type]
#endif
buf = tmpbuf;
+12 -2
View File
@@ -1,5 +1,5 @@
/* Update data structures for changes.
Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc.
Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006 Red Hat, Inc.
Written by Ulrich Drepper <drepper@redhat.com>, 2000.
This program is free software; you can redistribute it and/or modify
@@ -319,8 +319,18 @@ __elfw2(LIBELFBITS,updatenull) (Elf *elf, int *change_bop, size_t shnum)
scn->shdr_flags);
size = (size + sh_align - 1) & ~(sh_align - 1);
int offset_changed = 0;
update_if_changed (shdr->sh_offset, (GElf_Word) size,
changed);
offset_changed);
changed |= offset_changed;
if (offset_changed && scn->data_list_rear == NULL)
{
/* The position of the section in the file
changed. Create the section data list. */
if (INTUSE(elf_getdata) (scn, NULL) == NULL)
return -1;
}
/* See whether the section size is correct. */
update_if_changed (shdr->sh_size, (GElf_Word) offset,
+2 -10
View File
@@ -1,5 +1,5 @@
/* Update data structures for changes and write them out.
Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005 Red Hat, Inc.
Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006 Red Hat, Inc.
Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
This program is free software; you can redistribute it and/or modify
@@ -181,15 +181,7 @@ elf_update (elf, cmd)
size = -1;
}
else
{
if (elf->parent != NULL)
{
extern int puts (const char *);
puts ("this is an archive member");
}
size = write_file (elf, size, change_bo, shnum);
}
size = write_file (elf, size, change_bo, shnum);
}
out: