1 /* Write changed data structures.
2 Copyright (C) 2000, 2001, 2002 Red Hat, Inc.
3 Written by Ulrich Drepper <drepper@redhat.com>, 2000.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software Foundation,
16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
28 #include <sys/param.h>
34 # define LIBELFBITS 32
40 __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum)
42 ElfW2(LIBELFBITS,Ehdr) *ehdr;
46 /* We need the ELF header several times. */
47 ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
49 /* Write out the ELF header. */
50 if ((elf->state.ELFW(elf,LIBELFBITS).ehdr_flags | elf->flags) & ELF_F_DIRTY)
52 /* If the type sizes should be different at some time we have to
54 assert (sizeof (ElfW2(LIBELFBITS,Ehdr))
55 == elf_typesize (LIBELFBITS, ELF_T_EHDR, 1));
59 /* Today there is only one version of the ELF header. */
61 fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR];
64 # define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR]
67 /* Do the real work. */
68 (*fctp) ((char *) elf->map_address + elf->start_offset, ehdr,
69 sizeof (ElfW2(LIBELFBITS,Ehdr)), 1);
72 memcpy (elf->map_address + elf->start_offset, ehdr,
73 sizeof (ElfW2(LIBELFBITS,Ehdr)));
75 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY;
78 /* Write out the program header table. */
79 if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL
80 && ((elf->state.ELFW(elf,LIBELFBITS).phdr_flags | elf->flags)
83 /* If the type sizes should be different at some time we have to
85 assert (sizeof (ElfW2(LIBELFBITS,Phdr))
86 == elf_typesize (LIBELFBITS, ELF_T_PHDR, 1));
88 /* Maybe the user wants a gap between the ELF header and the program
90 if (ehdr->e_phoff > ehdr->e_ehsize)
91 memset (elf->map_address + elf->start_offset + ehdr->e_ehsize,
92 __libelf_fill_byte, ehdr->e_phoff - ehdr->e_ehsize);
96 /* Today there is only one version of the ELF header. */
98 fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR];
101 # define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR]
104 /* Do the real work. */
105 (*fctp) (elf->map_address + elf->start_offset + ehdr->e_phoff,
106 elf->state.ELFW(elf,LIBELFBITS).phdr,
107 sizeof (ElfW2(LIBELFBITS,Phdr)), ehdr->e_phnum);
110 memcpy (elf->map_address + elf->start_offset + ehdr->e_phoff,
111 elf->state.ELFW(elf,LIBELFBITS).phdr,
112 sizeof (ElfW2(LIBELFBITS,Phdr)) * ehdr->e_phnum);
114 elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY;
117 /* From now on we have to keep track of the last position to eventually
118 fill the gaps with the prescribed fill byte. */
119 last_position = ((char *) elf->map_address + elf->start_offset
120 + MAX (elf_typesize (LIBELFBITS, ELF_T_EHDR, 1),
122 + elf_typesize (LIBELFBITS, ELF_T_PHDR, ehdr->e_phnum));
124 /* Write all the sections. Well, only those which are modified. */
127 ElfW2(LIBELFBITS,Shdr) *shdr_dest;
128 Elf_ScnList *list = &elf->state.ELFW(elf,LIBELFBITS).scns;
131 xfct_t shdr_fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR];
134 # define shdr_fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR]
136 shdr_dest = (ElfW2(LIBELFBITS,Shdr) *)
137 ((char *) elf->map_address + elf->start_offset + ehdr->e_shoff);
143 for (cnt = 0; cnt < list->cnt; ++cnt)
145 ElfW2(LIBELFBITS,Shdr) *shdr;
149 shdr = list->data[cnt].shdr.ELFW(e,LIBELFBITS);
151 scn_start = ((char *) elf->map_address
152 + elf->start_offset + shdr->sh_offset);
153 dl = &list->data[cnt].data_list;
155 if (shdr->sh_type != SHT_NOBITS
156 && list->data[cnt].data_list_rear != NULL)
159 if ((list->data[cnt].flags | dl->flags
160 | elf->flags) & ELF_F_DIRTY)
162 if (scn_start + dl->data.d.d_off != last_position)
164 if (scn_start + dl->data.d.d_off > last_position)
165 memset (last_position, __libelf_fill_byte,
166 scn_start + dl->data.d.d_off
168 last_position = scn_start + dl->data.d.d_off;
176 fctp = __elf_xfctstom[__libelf_version - 1][dl->data.d.d_version - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type];
177 recsize = __libelf_type_sizes[dl->d_version - 1][ELFW(ELFCLASS,LIBELFBITS) - 1][dl->data.d.d_type];
180 fctp = __elf_xfctstom[0][0][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type];
181 recsize = __libelf_type_sizes[0][ELFW(ELFCLASS,LIBELFBITS) - 1][dl->data.d.d_type];
184 /* Make sure the data size matches the
186 assert (dl->data.d.d_size % recsize == 0);
188 /* Do the real work. */
189 (*fctp) (last_position, dl->data.d.d_buf, recsize,
190 dl->data.d.d_size / recsize);
192 last_position += dl->data.d.d_size;
195 last_position = mempcpy (last_position,
200 last_position += dl->data.d.d_size;
202 dl->flags &= ~ELF_F_DIRTY;
208 /* Write the section header table entry if necessary. */
209 if ((list->data[cnt].shdr_flags | elf->flags) & ELF_F_DIRTY)
212 (*shdr_fctp) (shdr_dest,
213 list->data[cnt].shdr.ELFW(e,LIBELFBITS),
214 sizeof (ElfW2(LIBELFBITS,Shdr)), 1);
216 memcpy (shdr_dest, list->data[cnt].shdr.ELFW(e,LIBELFBITS),
217 sizeof (ElfW2(LIBELFBITS,Shdr)));
219 list->data[cnt].shdr_flags &= ~ELF_F_DIRTY;
223 list->data[cnt].flags &= ~ELF_F_DIRTY;
226 assert (list->next == NULL || list->cnt == list->max);
228 while ((list = list->next) != NULL);
231 /* Fill the gap between last section and section header table if
233 if ((elf->flags & ELF_F_DIRTY)
234 && last_position != ((char *) elf->map_address + elf->start_offset
237 assert ((char *) elf->map_address + elf->start_offset + ehdr->e_shoff
239 memset (last_position, __libelf_fill_byte,
240 (char *) elf->map_address + elf->start_offset + ehdr->e_shoff
245 /* That was the last part. Clear the overall flag. */
246 elf->flags &= ~ELF_F_DIRTY;
252 /* Size of the buffer we use to generate the blocks of fill bytes. */
253 #define FILLBUFSIZE 4096
255 /* If we have to convert the section buffer contents we have to use
256 temporary buffer. Only buffers up to MAX_TMPBUF bytes are allocated
258 #define MAX_TMPBUF 32768
261 /* Helper function to write out fill bytes. */
263 fill (int fd, off_t pos, size_t len, char *fillbuf, size_t *filledp)
264 /*@modifies fillbuf, filledp @*/
266 size_t filled = *filledp;
268 if (unlikely (len > filled) && filled < FILLBUFSIZE)
270 /* Initialize a few more bytes. */
271 memset (fillbuf + filled, __libelf_fill_byte, len - filled);
272 *filledp = filled = len;
277 /* This many bytes we want to write in this round. */
278 size_t n = MIN (filled, len);
280 if (unlikely (pwrite (fd, fillbuf, n, pos) != n))
282 __libelf_seterrno (ELF_E_WRITE_ERROR);
297 __elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum)
299 char fillbuf[FILLBUFSIZE];
301 ElfW2(LIBELFBITS,Ehdr) *ehdr;
307 /* We need the ELF header several times. */
308 ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
310 /* Write out the ELF header. */
311 if ((elf->state.ELFW(elf,LIBELFBITS).ehdr_flags | elf->flags) & ELF_F_DIRTY)
313 ElfW2(LIBELFBITS,Ehdr) tmp_ehdr;
314 ElfW2(LIBELFBITS,Ehdr) *out_ehdr = ehdr;
316 /* If the type sizes should be different at some time we have to
317 rewrite this code. */
318 assert (sizeof (ElfW2(LIBELFBITS,Ehdr))
319 == elf_typesize (LIBELFBITS, ELF_T_EHDR, 1));
323 /* Today there is only one version of the ELF header. */
325 fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR];
328 # define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR]
331 /* Write the converted ELF header in a temporary buffer. */
332 (*fctp) (&tmp_ehdr, ehdr, sizeof (ElfW2(LIBELFBITS,Ehdr)), 1);
334 /* This is the buffer we want to write. */
335 out_ehdr = &tmp_ehdr;
338 /* Write out the ELF header. */
339 if (unlikely (pwrite (elf->fildes, out_ehdr,
340 sizeof (ElfW2(LIBELFBITS,Ehdr)), 0)
341 != sizeof (ElfW2(LIBELFBITS,Ehdr))))
343 __libelf_seterrno (ELF_E_WRITE_ERROR);
347 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY;
350 /* If the type sizes should be different at some time we have to
351 rewrite this code. */
352 assert (sizeof (ElfW2(LIBELFBITS,Phdr))
353 == elf_typesize (LIBELFBITS, ELF_T_PHDR, 1));
355 /* Write out the program header table. */
356 if ((elf->state.ELFW(elf,LIBELFBITS).phdr_flags | elf->flags) & ELF_F_DIRTY)
358 ElfW2(LIBELFBITS,Phdr) tmp_phdr;
359 ElfW2(LIBELFBITS,Phdr) *out_phdr = elf->state.ELFW(elf,LIBELFBITS).phdr;
361 /* Maybe the user wants a gap between the ELF header and the program
363 if (ehdr->e_phoff > ehdr->e_ehsize
364 && unlikely (fill (elf->fildes, ehdr->e_ehsize,
365 ehdr->e_phoff - ehdr->e_ehsize, fillbuf, &filled)
371 /* Today there is only one version of the ELF header. */
373 fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR];
376 # define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR]
379 /* Write the converted ELF header in a temporary buffer. */
380 (*fctp) (&tmp_phdr, elf->state.ELFW(elf,LIBELFBITS).phdr,
381 sizeof (ElfW2(LIBELFBITS,Phdr)), ehdr->e_phnum);
383 /* This is the buffer we want to write. */
384 out_phdr = &tmp_phdr;
387 /* Write out the ELF header. */
388 if (unlikely (pwrite (elf->fildes, out_phdr,
389 sizeof (ElfW2(LIBELFBITS,Phdr)) * ehdr->e_phnum,
391 != sizeof (ElfW2(LIBELFBITS,Phdr)) * ehdr->e_phnum))
393 __libelf_seterrno (ELF_E_WRITE_ERROR);
397 elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY;
400 /* From now on we have to keep track of the last position to eventually
401 fill the gaps with the prescribed fill byte. */
402 last_offset = (ehdr->e_phoff
403 + sizeof (ElfW2(LIBELFBITS,Phdr)) * ehdr->e_phnum);
405 /* Write all the sections. Well, only those which are modified. */
410 Elf_ScnList *list = &elf->state.ELFW(elf,LIBELFBITS).scns;
411 ElfW2(LIBELFBITS,Shdr) *shdr_data;
412 ElfW2(LIBELFBITS,Shdr) *shdr_data_begin;
415 shdr_offset = elf->start_offset + ehdr->e_shoff;
417 shdr_fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR];
420 # define shdr_fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR]
423 if (change_bo || elf->state.ELFW(elf,LIBELFBITS).shdr == NULL)
424 shdr_data = (ElfW2(LIBELFBITS,Shdr) *)
425 alloca (shnum * sizeof (ElfW2(LIBELFBITS,Shdr)));
427 shdr_data = elf->state.ELFW(elf,LIBELFBITS).shdr;
428 shdr_data_begin = shdr_data;
429 shdr_flags = elf->flags;
435 for (cnt = 0; cnt < list->cnt; ++cnt)
437 ElfW2(LIBELFBITS,Shdr) *shdr;
441 shdr = list->data[cnt].shdr.ELFW(e,LIBELFBITS);
443 scn_start = elf->start_offset + shdr->sh_offset;
444 dl = &list->data[cnt].data_list;
446 if (shdr->sh_type != SHT_NOBITS
447 && list->data[cnt].data_list_rear != NULL
448 && list->data[cnt].index != 0)
451 if ((list->data[cnt].flags | dl->flags
452 | elf->flags) & ELF_F_DIRTY)
454 char tmpbuf[MAX_TMPBUF];
455 void *buf = dl->data.d.d_buf;
457 if (scn_start + dl->data.d.d_off != last_offset)
460 < scn_start + dl->data.d.d_off);
462 if (unlikely (fill (elf->fildes, last_offset,
463 (scn_start + dl->data.d.d_off)
464 - last_offset, fillbuf,
468 last_offset = scn_start + dl->data.d.d_off;
476 fctp = __elf_xfctstom[__libelf_version - 1][dl->data.d.d_version - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type];
477 recsize = __libelf_type_sizes[dl->d_version - 1][ELFW(ELFCLASS,LIBELFBITS) - 1][dl->data.d.d_type];
479 fctp = __elf_xfctstom[0][0][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type];
480 recsize = __libelf_type_sizes[0][ELFW(ELFCLASS,LIBELFBITS) - 1][dl->data.d.d_type];
483 /* Make sure the data size matches the
485 assert (dl->data.d.d_size % recsize == 0);
488 if (dl->data.d.d_size > MAX_TMPBUF)
490 buf = malloc (dl->data.d.d_size);
493 __libelf_seterrno (ELF_E_NOMEM);
498 /* Do the real work. */
499 (*fctp) (buf, dl->data.d.d_buf, recsize,
500 dl->data.d.d_size / recsize);
503 if (unlikely (pwrite (elf->fildes, buf,
504 dl->data.d.d_size, last_offset)
505 != dl->data.d.d_size))
507 if (buf != dl->data.d.d_buf && buf != tmpbuf)
510 __libelf_seterrno (ELF_E_WRITE_ERROR);
514 if (buf != dl->data.d.d_buf && buf != tmpbuf)
518 last_offset += dl->data.d.d_size;
520 dl->flags &= ~ELF_F_DIRTY;
526 /* Collect the section header table information. */
528 (*shdr_fctp) (shdr_data++,
529 list->data[cnt].shdr.ELFW(e,LIBELFBITS),
530 sizeof (ElfW2(LIBELFBITS,Shdr)), 1);
531 else if (elf->state.ELFW(elf,LIBELFBITS).shdr == NULL)
532 shdr_data = mempcpy (shdr_data,
533 list->data[cnt].shdr.ELFW(e,LIBELFBITS),
534 sizeof (ElfW2(LIBELFBITS,Shdr)));
536 shdr_flags |= list->data[cnt].shdr_flags;
537 list->data[cnt].shdr_flags &= ~ELF_F_DIRTY;
540 while ((list = list->next) != NULL);
543 assert (shdr_data == &shdr_data_begin[shnum]);
545 /* Write out the section header table. */
546 if (shdr_flags & ELF_F_DIRTY
547 && unlikely (pwrite (elf->fildes, shdr_data_begin,
548 sizeof (ElfW2(LIBELFBITS,Shdr)) * shnum,
550 != sizeof (ElfW2(LIBELFBITS,Shdr)) * shnum))
552 __libelf_seterrno (ELF_E_WRITE_ERROR);
557 /* That was the last part. Clear the overall flag. */
558 elf->flags &= ~ELF_F_DIRTY;