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
260 /* Helper function to write out fill bytes. */
262 fill (int fd, off_t pos, size_t len, char *fillbuf, size_t *filledp)
263 /*@modifies fillbuf, filledp @*/
265 size_t filled = *filledp;
266 size_t fill_len = MIN (len, FILLBUFSIZE);
268 if (unlikely (fill_len > filled) && (filled < FILLBUFSIZE))
270 /* Initialize a few more bytes. */
271 memset (fillbuf + filled, __libelf_fill_byte, fill_len - filled);
272 *filledp = filled = fill_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 != NULL
357 && (elf->state.ELFW(elf,LIBELFBITS).phdr_flags | elf->flags) & ELF_F_DIRTY)
359 ElfW2(LIBELFBITS,Phdr) tmp_phdr;
360 ElfW2(LIBELFBITS,Phdr) *out_phdr = elf->state.ELFW(elf,LIBELFBITS).phdr;
362 /* Maybe the user wants a gap between the ELF header and the program
364 if (ehdr->e_phoff > ehdr->e_ehsize
365 && unlikely (fill (elf->fildes, ehdr->e_ehsize,
366 ehdr->e_phoff - ehdr->e_ehsize, fillbuf, &filled)
372 /* Today there is only one version of the ELF header. */
374 fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR];
377 # define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR]
380 /* Write the converted ELF header in a temporary buffer. */
381 (*fctp) (&tmp_phdr, elf->state.ELFW(elf,LIBELFBITS).phdr,
382 sizeof (ElfW2(LIBELFBITS,Phdr)), ehdr->e_phnum);
384 /* This is the buffer we want to write. */
385 out_phdr = &tmp_phdr;
388 /* Write out the ELF header. */
389 if (unlikely (pwrite (elf->fildes, out_phdr,
390 sizeof (ElfW2(LIBELFBITS,Phdr)) * ehdr->e_phnum,
392 != sizeof (ElfW2(LIBELFBITS,Phdr)) * ehdr->e_phnum))
394 __libelf_seterrno (ELF_E_WRITE_ERROR);
398 elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY;
401 /* From now on we have to keep track of the last position to eventually
402 fill the gaps with the prescribed fill byte. */
403 last_offset = (ehdr->e_phoff
404 + sizeof (ElfW2(LIBELFBITS,Phdr)) * ehdr->e_phnum);
406 /* Write all the sections. Well, only those which are modified. */
411 Elf_ScnList *list = &elf->state.ELFW(elf,LIBELFBITS).scns;
412 ElfW2(LIBELFBITS,Shdr) *shdr_data;
413 ElfW2(LIBELFBITS,Shdr) *shdr_data_begin;
416 shdr_offset = elf->start_offset + ehdr->e_shoff;
418 shdr_fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR];
421 # define shdr_fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR]
424 if (change_bo || elf->state.ELFW(elf,LIBELFBITS).shdr == NULL)
425 shdr_data = (ElfW2(LIBELFBITS,Shdr) *)
426 alloca (shnum * sizeof (ElfW2(LIBELFBITS,Shdr)));
428 shdr_data = elf->state.ELFW(elf,LIBELFBITS).shdr;
429 shdr_data_begin = shdr_data;
430 shdr_flags = elf->flags;
436 for (cnt = 0; cnt < list->cnt; ++cnt)
438 ElfW2(LIBELFBITS,Shdr) *shdr;
442 shdr = list->data[cnt].shdr.ELFW(e,LIBELFBITS);
444 scn_start = elf->start_offset + shdr->sh_offset;
445 dl = &list->data[cnt].data_list;
447 if (shdr->sh_type != SHT_NOBITS
448 && list->data[cnt].data_list_rear != NULL
449 && list->data[cnt].index != 0)
452 if ((list->data[cnt].flags | dl->flags
453 | elf->flags) & ELF_F_DIRTY)
455 char tmpbuf[MAX_TMPBUF];
456 void *buf = dl->data.d.d_buf;
458 if (scn_start + dl->data.d.d_off != last_offset)
461 < scn_start + dl->data.d.d_off);
463 if (unlikely (fill (elf->fildes, last_offset,
464 (scn_start + dl->data.d.d_off)
465 - last_offset, fillbuf,
469 last_offset = scn_start + dl->data.d.d_off;
477 fctp = __elf_xfctstom[__libelf_version - 1][dl->data.d.d_version - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type];
478 recsize = __libelf_type_sizes[dl->d_version - 1][ELFW(ELFCLASS,LIBELFBITS) - 1][dl->data.d.d_type];
480 fctp = __elf_xfctstom[0][0][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type];
481 recsize = __libelf_type_sizes[0][ELFW(ELFCLASS,LIBELFBITS) - 1][dl->data.d.d_type];
484 /* Make sure the data size matches the
486 assert (dl->data.d.d_size % recsize == 0);
489 if (dl->data.d.d_size > MAX_TMPBUF)
491 buf = malloc (dl->data.d.d_size);
494 __libelf_seterrno (ELF_E_NOMEM);
499 /* Do the real work. */
500 (*fctp) (buf, dl->data.d.d_buf, recsize,
501 dl->data.d.d_size / recsize);
504 if (unlikely (pwrite (elf->fildes, buf,
505 dl->data.d.d_size, last_offset)
506 != dl->data.d.d_size))
508 if (buf != dl->data.d.d_buf && buf != tmpbuf)
511 __libelf_seterrno (ELF_E_WRITE_ERROR);
515 if (buf != dl->data.d.d_buf && buf != tmpbuf)
519 last_offset += dl->data.d.d_size;
521 dl->flags &= ~ELF_F_DIRTY;
527 /* Collect the section header table information. */
529 (*shdr_fctp) (shdr_data++,
530 list->data[cnt].shdr.ELFW(e,LIBELFBITS),
531 sizeof (ElfW2(LIBELFBITS,Shdr)), 1);
532 else if (elf->state.ELFW(elf,LIBELFBITS).shdr == NULL)
533 shdr_data = mempcpy (shdr_data,
534 list->data[cnt].shdr.ELFW(e,LIBELFBITS),
535 sizeof (ElfW2(LIBELFBITS,Shdr)));
537 shdr_flags |= list->data[cnt].shdr_flags;
538 list->data[cnt].shdr_flags &= ~ELF_F_DIRTY;
541 while ((list = list->next) != NULL);
543 if (change_bo || elf->state.ELFW(elf,LIBELFBITS).shdr == NULL)
544 assert (shdr_data == &shdr_data_begin[shnum]);
546 /* Write out the section header table. */
547 if (shdr_flags & ELF_F_DIRTY
548 && unlikely (pwrite (elf->fildes, shdr_data_begin,
549 sizeof (ElfW2(LIBELFBITS,Shdr)) * shnum,
551 != sizeof (ElfW2(LIBELFBITS,Shdr)) * shnum))
553 __libelf_seterrno (ELF_E_WRITE_ERROR);
558 /* That was the last part. Clear the overall flag. */
559 elf->flags &= ~ELF_F_DIRTY;