internal_function
__elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum)
{
- ElfW2(LIBELFBITS,Ehdr) *ehdr;
- char *last_position;
+ bool previous_scn_changed = false;
/* We need the ELF header several times. */
- ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
+ ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
/* Write out the ELF header. */
if ((elf->state.ELFW(elf,LIBELFBITS).ehdr_flags | elf->flags) & ELF_F_DIRTY)
sizeof (ElfW2(LIBELFBITS,Ehdr)));
elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY;
+
+ /* We start writing sections after the ELF header only if there is
+ no program header. */
+ previous_scn_changed = elf->state.ELFW(elf,LIBELFBITS).phdr == NULL;
}
/* Write out the program header table. */
sizeof (ElfW2(LIBELFBITS,Phdr)) * ehdr->e_phnum);
elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY;
+
+ /* We modified the program header. Maybe this created a gap so
+ we have to write fill bytes, if necessary. */
+ previous_scn_changed = true;
}
/* From now on we have to keep track of the last position to eventually
fill the gaps with the prescribed fill byte. */
- last_position = ((char *) elf->map_address + elf->start_offset
- + MAX (elf_typesize (LIBELFBITS, ELF_T_EHDR, 1),
- ehdr->e_phoff)
- + elf_typesize (LIBELFBITS, ELF_T_PHDR, ehdr->e_phnum));
+ char *last_position = ((char *) elf->map_address + elf->start_offset
+ + MAX (elf_typesize (LIBELFBITS, ELF_T_EHDR, 1),
+ ehdr->e_phoff)
+ + elf_typesize (LIBELFBITS, ELF_T_PHDR,
+ ehdr->e_phnum));
/* Write all the sections. Well, only those which are modified. */
if (shnum > 0)
if (scn->index == 0)
{
/* The dummy section header entry. It should not be
- possible to make this "section" as dirty. */
+ possible to mark this "section" as dirty. */
assert ((scn->flags & ELF_F_DIRTY) == 0);
continue;
}
char *scn_start = ((char *) elf->map_address
+ elf->start_offset + shdr->sh_offset);
Elf_Data_List *dl = &scn->data_list;
+ bool scn_changed = false;
+
+ void fill_mmap (size_t offset)
+ {
+ size_t written = 0;
+
+ if (last_position < shdr_start)
+ {
+ written = MIN (scn_start + offset - last_position,
+ shdr_start - last_position);
+
+ memset (last_position, __libelf_fill_byte, written);
+ }
+
+ if (last_position + written != scn_start + offset
+ && shdr_end < scn_start + offset)
+ memset (shdr_end, __libelf_fill_byte,
+ scn_start + offset - shdr_end);
+ }
if (scn->data_list_rear != NULL)
do
assert (dl->data.d.d_size <= (shdr->sh_size
- (GElf_Off) dl->data.d.d_off));
+ /* If there is a gap, fill it. */
+ if (scn_start + dl->data.d.d_off > last_position
+ && ((previous_scn_changed && dl->data.d.d_off == 0)
+ || ((scn->flags | dl->flags | elf->flags)
+ & ELF_F_DIRTY) != 0))
+ fill_mmap (dl->data.d.d_off);
+
if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY)
{
- if (scn_start + dl->data.d.d_off > last_position)
- {
- /* This code assumes that the data blocks for
- a section are ordered by offset. */
- size_t written = 0;
-
- if (last_position < shdr_start)
- {
- written = MIN (scn_start + dl->data.d.d_off
- - last_position,
- shdr_start - last_position);
-
- memset (last_position, __libelf_fill_byte,
- written);
- }
-
- if (last_position + written
- != scn_start + dl->data.d.d_off
- && shdr_end < scn_start + dl->data.d.d_off)
- memset (shdr_end, __libelf_fill_byte,
- scn_start + dl->data.d.d_off - shdr_end);
- }
-
/* Let it go backward if the sections use a bogus
layout with overlaps. We'll overwrite the stupid
user's section data with the latest one, rather than
last_position = mempcpy (last_position,
dl->data.d.d_buf,
dl->data.d.d_size);
+
+ scn_changed = true;
}
else
last_position += dl->data.d.d_size;
}
while (dl != NULL);
else
- /* We have to trust the existing section header information. */
- last_position = scn_start + shdr->sh_size;
+ {
+ /* If the previous section (or the ELF/program
+ header) changed we might have to fill the gap. */
+ if (scn_start > last_position && previous_scn_changed)
+ fill_mmap (0);
+
+ /* We have to trust the existing section header information. */
+ last_position = scn_start + shdr->sh_size;
+ }
+
+ previous_scn_changed = scn_changed;
next:
scn->flags &= ~ELF_F_DIRTY;
}
{
char fillbuf[FILLBUFSIZE];
size_t filled = 0;
+ bool previous_scn_changed = false;
/* We need the ELF header several times. */
ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
}
elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY;
+
+ /* We start writing sections after the ELF header only if there is
+ no program header. */
+ previous_scn_changed = elf->state.ELFW(elf,LIBELFBITS).phdr == NULL;
}
/* If the type sizes should be different at some time we have to
free (tmp_phdr);
elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY;
+
+ /* We modified the program header. Maybe this created a gap so
+ we have to write fill bytes, if necessary. */
+ previous_scn_changed = true;
}
/* From now on we have to keep track of the last position to eventually
if (scn->index == 0)
{
/* The dummy section header entry. It should not be
- possible to make this "section" as dirty. */
+ possible to mark this "section" as dirty. */
assert ((scn->flags & ELF_F_DIRTY) == 0);
continue;
}
off_t scn_start = elf->start_offset + shdr->sh_offset;
Elf_Data_List *dl = &scn->data_list;
+ bool scn_changed = false;
if (scn->data_list_rear != NULL)
do
{
+ /* If there is a gap, fill it. */
+ if (scn_start + dl->data.d.d_off > last_offset
+ && ((previous_scn_changed && dl->data.d.d_off == 0)
+ || ((scn->flags | dl->flags | elf->flags)
+ & ELF_F_DIRTY) != 0))
+ {
+ if (unlikely (fill (elf->fildes, last_offset,
+ (scn_start + dl->data.d.d_off)
+ - last_offset, fillbuf,
+ &filled) != 0))
+ return 1;
+ }
+
if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY)
{
char tmpbuf[MAX_TMPBUF];
void *buf = dl->data.d.d_buf;
- if (scn_start + dl->data.d.d_off > last_offset)
- {
- if (unlikely (fill (elf->fildes, last_offset,
- (scn_start + dl->data.d.d_off)
- - last_offset, fillbuf,
- &filled) != 0))
- return 1;
- }
-
/* Let it go backward if the sections use a bogus
layout with overlaps. We'll overwrite the stupid
user's section data with the latest one, rather than
if (buf != dl->data.d.d_buf && buf != tmpbuf)
free (buf);
+
+ scn_changed = true;
}
last_offset += dl->data.d.d_size;
}
while (dl != NULL);
else
- last_offset = scn_start + shdr->sh_size;
+ {
+ /* If the previous section (or the ELF/program
+ header) changed we might have to fill the gap. */
+ if (scn_start > last_offset && previous_scn_changed)
+ {
+ if (unlikely (fill (elf->fildes, last_offset,
+ scn_start - last_offset, fillbuf,
+ &filled) != 0))
+ return 1;
+ }
+
+ last_offset = scn_start + shdr->sh_size;
+ }
+ previous_scn_changed = scn_changed;
next:
/* Collect the section header table information. */
if (unlikely (change_bo))