blob: 7561a685d3742f98ecdc98b12125a6393976ba9f [file] [log] [blame]
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001/* Write changed data structures.
Ulrich Drepper697d8d22006-04-04 21:07:28 +00002 Copyright (C) 2000, 2001, 2002, 2004, 2005, 2006 Red Hat, Inc.
Ulrich Drepper361df7d2006-04-04 21:38:57 +00003 This file is part of Red Hat elfutils.
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004 Written by Ulrich Drepper <drepper@redhat.com>, 2000.
5
Ulrich Drepper361df7d2006-04-04 21:38:57 +00006 Red Hat elfutils is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by the
8 Free Software Foundation; version 2 of the License.
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00009
Ulrich Drepper361df7d2006-04-04 21:38:57 +000010 Red Hat elfutils is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000014
Ulrich Drepper361df7d2006-04-04 21:38:57 +000015 You should have received a copy of the GNU General Public License along
16 with Red Hat elfutils; if not, write to the Free Software Foundation,
Ulrich Drepper1e9ef502006-04-04 22:29:06 +000017 Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
Ulrich Drepper361df7d2006-04-04 21:38:57 +000018
19 In addition, as a special exception, Red Hat, Inc. gives You the
20 additional right to link the code of Red Hat elfutils with code licensed
21 under any Open Source Initiative certified open source license
22 (http://www.opensource.org/licenses/index.php) which requires the
23 distribution of source code with any binary distribution and to
24 distribute linked combinations of the two. Non-GPL Code permitted under
25 this exception must only link to the code of Red Hat elfutils through
26 those well defined interfaces identified in the file named EXCEPTION
27 found in the source code files (the "Approved Interfaces"). The files
28 of Non-GPL Code may instantiate templates or use macros or inline
29 functions from the Approved Interfaces without causing the resulting
30 work to be covered by the GNU General Public License. Only Red Hat,
31 Inc. may make changes or additions to the list of Approved Interfaces.
32 Red Hat's grant of this exception is conditioned upon your not adding
33 any new exceptions. If you wish to add a new Approved Interface or
34 exception, please contact Red Hat. You must obey the GNU General Public
35 License in all respects for all of the Red Hat elfutils code and other
36 code used in conjunction with Red Hat elfutils except the Non-GPL Code
37 covered by this exception. If you modify this file, you may extend this
38 exception to your version of the file, but you are not obligated to do
39 so. If you do not wish to provide this exception without modification,
40 you must delete this exception statement from your version and license
41 this file solely under the GPL without exception.
42
43 Red Hat elfutils is an included package of the Open Invention Network.
44 An included package of the Open Invention Network is a package for which
45 Open Invention Network licensees cross-license their patents. No patent
46 license is granted, either expressly or impliedly, by designation as an
47 included package. Should you wish to participate in the Open Invention
48 Network licensing program, please visit www.openinventionnetwork.com
49 <http://www.openinventionnetwork.com>. */
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000050
51#ifdef HAVE_CONFIG_H
52# include <config.h>
53#endif
54
55#include <assert.h>
Ulrich Drepperfbe998a2005-08-29 16:27:10 +000056#include <errno.h>
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000057#include <libelf.h>
58#include <stdbool.h>
59#include <stdlib.h>
60#include <string.h>
61#include <unistd.h>
Ulrich Drepper697d8d22006-04-04 21:07:28 +000062#include <sys/mman.h>
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000063#include <sys/param.h>
64
Ulrich Drepperfbe998a2005-08-29 16:27:10 +000065#include <system.h>
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000066#include "libelfP.h"
67
68
69#ifndef LIBELFBITS
70# define LIBELFBITS 32
71#endif
72
73
74static int
75compare_sections (const void *a, const void *b)
76{
77 const Elf_Scn **scna = (const Elf_Scn **) a;
78 const Elf_Scn **scnb = (const Elf_Scn **) b;
79
80 if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_offset
81 < (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_offset)
82 return -1;
83
84 if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_offset
85 > (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_offset)
86 return 1;
87
88 if ((*scna)->index < (*scnb)->index)
89 return -1;
90
91 if ((*scna)->index > (*scnb)->index)
92 return 1;
93
94 return 0;
95}
96
97
98/* Insert the sections in the list into the provided array and sort
99 them according to their start offsets. For sections with equal
100 start offsets the section index is used. */
101static void
102sort_sections (Elf_Scn **scns, Elf_ScnList *list)
103{
104 Elf_Scn **scnp = scns;
105 do
106 for (size_t cnt = 0; cnt < list->cnt; ++cnt)
107 *scnp++ = &list->data[cnt];
108 while ((list = list->next) != NULL);
109
110 qsort (scns, scnp - scns, sizeof (*scns), compare_sections);
111}
112
113
114int
115internal_function_def
116__elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum)
117{
118 ElfW2(LIBELFBITS,Ehdr) *ehdr;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000119 char *last_position;
120
121 /* We need the ELF header several times. */
122 ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
123
124 /* Write out the ELF header. */
125 if ((elf->state.ELFW(elf,LIBELFBITS).ehdr_flags | elf->flags) & ELF_F_DIRTY)
126 {
127 /* If the type sizes should be different at some time we have to
128 rewrite this code. */
129 assert (sizeof (ElfW2(LIBELFBITS,Ehdr))
130 == elf_typesize (LIBELFBITS, ELF_T_EHDR, 1));
131
132 if (unlikely (change_bo))
133 {
134 /* Today there is only one version of the ELF header. */
135#if EV_NUM != 2
Ulrich Drepper697d8d22006-04-04 21:07:28 +0000136 xfct_t fctp;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000137 fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR];
138#else
139# undef fctp
140# define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR]
141#endif
142
143 /* Do the real work. */
144 (*fctp) ((char *) elf->map_address + elf->start_offset, ehdr,
145 sizeof (ElfW2(LIBELFBITS,Ehdr)), 1);
146 }
147 else
148 memcpy (elf->map_address + elf->start_offset, ehdr,
149 sizeof (ElfW2(LIBELFBITS,Ehdr)));
150
151 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY;
152 }
153
154 /* Write out the program header table. */
155 if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL
156 && ((elf->state.ELFW(elf,LIBELFBITS).phdr_flags | elf->flags)
157 & ELF_F_DIRTY))
158 {
159 /* If the type sizes should be different at some time we have to
160 rewrite this code. */
161 assert (sizeof (ElfW2(LIBELFBITS,Phdr))
162 == elf_typesize (LIBELFBITS, ELF_T_PHDR, 1));
163
164 /* Maybe the user wants a gap between the ELF header and the program
165 header. */
166 if (ehdr->e_phoff > ehdr->e_ehsize)
167 memset (elf->map_address + elf->start_offset + ehdr->e_ehsize,
168 __libelf_fill_byte, ehdr->e_phoff - ehdr->e_ehsize);
169
170 if (unlikely (change_bo))
171 {
172 /* Today there is only one version of the ELF header. */
173#if EV_NUM != 2
Ulrich Drepper697d8d22006-04-04 21:07:28 +0000174 xfct_t fctp;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000175 fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR];
176#else
177# undef fctp
178# define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR]
179#endif
180
181 /* Do the real work. */
182 (*fctp) (elf->map_address + elf->start_offset + ehdr->e_phoff,
183 elf->state.ELFW(elf,LIBELFBITS).phdr,
184 sizeof (ElfW2(LIBELFBITS,Phdr)) * ehdr->e_phnum, 1);
185 }
186 else
187 memcpy (elf->map_address + elf->start_offset + ehdr->e_phoff,
188 elf->state.ELFW(elf,LIBELFBITS).phdr,
189 sizeof (ElfW2(LIBELFBITS,Phdr)) * ehdr->e_phnum);
190
191 elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY;
192 }
193
194 /* From now on we have to keep track of the last position to eventually
195 fill the gaps with the prescribed fill byte. */
196 last_position = ((char *) elf->map_address + elf->start_offset
197 + MAX (elf_typesize (LIBELFBITS, ELF_T_EHDR, 1),
198 ehdr->e_phoff)
199 + elf_typesize (LIBELFBITS, ELF_T_PHDR, ehdr->e_phnum));
200
201 /* Write all the sections. Well, only those which are modified. */
202 if (shnum > 0)
203 {
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000204 Elf_ScnList *list = &elf->state.ELFW(elf,LIBELFBITS).scns;
205 Elf_Scn **scns = (Elf_Scn **) alloca (shnum * sizeof (Elf_Scn *));
Ulrich Drepper697d8d22006-04-04 21:07:28 +0000206 char *const shdr_start = ((char *) elf->map_address + elf->start_offset
207 + ehdr->e_shoff);
208 char *const shdr_end = shdr_start + ehdr->e_shnum * ehdr->e_shentsize;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000209
210#if EV_NUM != 2
211 xfct_t shdr_fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR];
212#else
213# undef shdr_fctp
214# define shdr_fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR]
215#endif
Ulrich Drepper697d8d22006-04-04 21:07:28 +0000216#define shdr_dest ((ElfW2(LIBELFBITS,Shdr) *) shdr_start)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000217
218 /* Get all sections into the array and sort them. */
219 sort_sections (scns, list);
220
Ulrich Drepper697d8d22006-04-04 21:07:28 +0000221 /* We possibly have to copy the section header data because moving
222 the sections might overwrite the data. */
223 for (size_t cnt = 0; cnt < shnum; ++cnt)
224 {
225 Elf_Scn *scn = scns[cnt];
226
Roland McGrathb4379722006-04-05 01:35:26 +0000227 if (!elf->state.ELFW(elf,LIBELFBITS).shdr_malloced
228 && (scn->shdr_flags & ELF_F_MALLOCED) == 0
Ulrich Drepper697d8d22006-04-04 21:07:28 +0000229 && scn->shdr.ELFW(e,LIBELFBITS) != &shdr_dest[scn->index])
230 {
231 assert ((char *) elf->map_address + elf->start_offset
232 < (char *) scn->shdr.ELFW(e,LIBELFBITS));
233 assert ((char *) scn->shdr.ELFW(e,LIBELFBITS)
Ulrich Drepper3a5052a2006-04-05 03:13:34 +0000234 < ((char *) elf->map_address + elf->start_offset
235 + elf->maximum_size));
Ulrich Drepper697d8d22006-04-04 21:07:28 +0000236
237 void *p = alloca (sizeof (ElfW2(LIBELFBITS,Shdr)));
238 scn->shdr.ELFW(e,LIBELFBITS)
239 = memcpy (p, scn->shdr.ELFW(e,LIBELFBITS),
240 sizeof (ElfW2(LIBELFBITS,Shdr)));
241 }
242 }
243
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000244 /* Iterate over all the section in the order in which they
245 appear in the output file. */
246 for (size_t cnt = 0; cnt < shnum; ++cnt)
247 {
248 Elf_Scn *scn = scns[cnt];
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000249
Ulrich Drepper697d8d22006-04-04 21:07:28 +0000250 ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000251
Ulrich Drepper697d8d22006-04-04 21:07:28 +0000252 char *scn_start = ((char *) elf->map_address
253 + elf->start_offset + shdr->sh_offset);
254 Elf_Data_List *dl = &scn->data_list;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000255
256 if (shdr->sh_type != SHT_NOBITS && scn->data_list_rear != NULL)
257 do
258 {
259 if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY)
260 {
261 if (scn_start + dl->data.d.d_off != last_position)
262 {
263 if (scn_start + dl->data.d.d_off > last_position)
264 {
265 /* This code assumes that the data blocks for
266 a section are ordered by offset. */
267 size_t written = 0;
268
269 if (last_position < shdr_start)
270 {
271 written = MIN (scn_start + dl->data.d.d_off
272 - last_position,
273 shdr_start - last_position);
274
275 memset (last_position, __libelf_fill_byte,
276 written);
277 }
278
279 if (last_position + written
280 != scn_start + dl->data.d.d_off
281 && shdr_end < scn_start + dl->data.d.d_off)
282 memset (shdr_end, __libelf_fill_byte,
283 scn_start + dl->data.d.d_off - shdr_end);
284
285 last_position = scn_start + dl->data.d.d_off;
286 }
287 }
288
289 if (unlikely (change_bo))
290 {
291#if EV_NUM != 2
Ulrich Drepper697d8d22006-04-04 21:07:28 +0000292 xfct_t fctp;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000293 fctp = __elf_xfctstom[__libelf_version - 1][dl->data.d.d_version - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type];
294#else
295# undef fctp
Ulrich Drepper697d8d22006-04-04 21:07:28 +0000296# define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type]
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000297#endif
298
299 /* Do the real work. */
300 (*fctp) (last_position, dl->data.d.d_buf,
301 dl->data.d.d_size, 1);
302
303 last_position += dl->data.d.d_size;
304 }
305 else
306 last_position = mempcpy (last_position,
307 dl->data.d.d_buf,
308 dl->data.d.d_size);
309 }
310 else
311 last_position += dl->data.d.d_size;
312
313 dl->flags &= ~ELF_F_DIRTY;
314
315 dl = dl->next;
316 }
317 while (dl != NULL);
318 else if (shdr->sh_type != SHT_NOBITS && scn->index != 0)
319 /* We have to trust the existing section header information. */
320 last_position += shdr->sh_size;
321
Ulrich Drepper697d8d22006-04-04 21:07:28 +0000322 scn->flags &= ~ELF_F_DIRTY;
323 }
324
325 /* Fill the gap between last section and section header table if
326 necessary. */
327 if ((elf->flags & ELF_F_DIRTY)
328 && last_position < ((char *) elf->map_address + elf->start_offset
329 + ehdr->e_shoff))
330 memset (last_position, __libelf_fill_byte,
331 (char *) elf->map_address + elf->start_offset + ehdr->e_shoff
332 - last_position);
333
334 /* Write the section header table entry if necessary. */
335 for (size_t cnt = 0; cnt < shnum; ++cnt)
336 {
337 Elf_Scn *scn = scns[cnt];
338
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000339 if ((scn->shdr_flags | elf->flags) & ELF_F_DIRTY)
340 {
341 if (unlikely (change_bo))
342 (*shdr_fctp) (&shdr_dest[scn->index],
343 scn->shdr.ELFW(e,LIBELFBITS),
344 sizeof (ElfW2(LIBELFBITS,Shdr)), 1);
345 else
346 memcpy (&shdr_dest[scn->index],
347 scn->shdr.ELFW(e,LIBELFBITS),
348 sizeof (ElfW2(LIBELFBITS,Shdr)));
349
Ulrich Drepper697d8d22006-04-04 21:07:28 +0000350 /* If we previously made a copy of the section header
351 entry we now have to adjust the pointer again so
352 point to new place in the mapping. */
Roland McGrathb4379722006-04-05 01:35:26 +0000353 if (!elf->state.ELFW(elf,LIBELFBITS).shdr_malloced
354 && (scn->shdr_flags & ELF_F_MALLOCED) == 0)
Ulrich Drepper697d8d22006-04-04 21:07:28 +0000355 scn->shdr.ELFW(e,LIBELFBITS) = &shdr_dest[scn->index];
356
Roland McGrathb4379722006-04-05 01:35:26 +0000357 scn->shdr_flags &= ~ELF_F_DIRTY;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000358 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000359 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000360 }
361
362 /* That was the last part. Clear the overall flag. */
363 elf->flags &= ~ELF_F_DIRTY;
364
Ulrich Drepper697d8d22006-04-04 21:07:28 +0000365 /* Make sure the content hits the disk. */
366 char *msync_start = ((char *) elf->map_address
367 + elf->start_offset / sysconf (_SC_PAGESIZE));
368 char *msync_end = ((char *) elf->map_address
369 + elf->start_offset + ehdr->e_shoff
370 * ehdr->e_shentsize * shnum);
371 (void) msync (msync_start, msync_end - msync_start, MS_SYNC);
372
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000373 return 0;
374}
375
376
377/* Size of the buffer we use to generate the blocks of fill bytes. */
378#define FILLBUFSIZE 4096
379
380/* If we have to convert the section buffer contents we have to use
381 temporary buffer. Only buffers up to MAX_TMPBUF bytes are allocated
382 on the stack. */
383#define MAX_TMPBUF 32768
384
385
386/* Helper function to write out fill bytes. */
387static int
388fill (int fd, off_t pos, size_t len, char *fillbuf, size_t *filledp)
389{
390 size_t filled = *filledp;
391 size_t fill_len = MIN (len, FILLBUFSIZE);
392
393 if (unlikely (fill_len > filled) && filled < FILLBUFSIZE)
394 {
395 /* Initialize a few more bytes. */
396 memset (fillbuf + filled, __libelf_fill_byte, fill_len - filled);
397 *filledp = filled = fill_len;
398 }
399
400 do
401 {
402 /* This many bytes we want to write in this round. */
403 size_t n = MIN (filled, len);
404
Ulrich Drepperfbe998a2005-08-29 16:27:10 +0000405 if (unlikely ((size_t) pwrite_retry (fd, fillbuf, n, pos) != n))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000406 {
407 __libelf_seterrno (ELF_E_WRITE_ERROR);
408 return 1;
409 }
410
411 pos += n;
412 len -= n;
413 }
414 while (len > 0);
415
416 return 0;
417}
418
419
420int
421internal_function_def
422__elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum)
423{
424 char fillbuf[FILLBUFSIZE];
425 size_t filled = 0;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000426
427 /* We need the ELF header several times. */
428 ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
429
430 /* Write out the ELF header. */
431 if ((elf->state.ELFW(elf,LIBELFBITS).ehdr_flags | elf->flags) & ELF_F_DIRTY)
432 {
433 ElfW2(LIBELFBITS,Ehdr) tmp_ehdr;
434 ElfW2(LIBELFBITS,Ehdr) *out_ehdr = ehdr;
435
436 /* If the type sizes should be different at some time we have to
437 rewrite this code. */
438 assert (sizeof (ElfW2(LIBELFBITS,Ehdr))
439 == elf_typesize (LIBELFBITS, ELF_T_EHDR, 1));
440
441 if (unlikely (change_bo))
442 {
443 /* Today there is only one version of the ELF header. */
444#if EV_NUM != 2
Ulrich Drepper697d8d22006-04-04 21:07:28 +0000445 xfct_t fctp;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000446 fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR];
447#else
448# undef fctp
449# define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR]
450#endif
451
452 /* Write the converted ELF header in a temporary buffer. */
453 (*fctp) (&tmp_ehdr, ehdr, sizeof (ElfW2(LIBELFBITS,Ehdr)), 1);
454
455 /* This is the buffer we want to write. */
456 out_ehdr = &tmp_ehdr;
457 }
458
459 /* Write out the ELF header. */
Ulrich Drepperfbe998a2005-08-29 16:27:10 +0000460 if (unlikely (pwrite_retry (elf->fildes, out_ehdr,
461 sizeof (ElfW2(LIBELFBITS,Ehdr)), 0)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000462 != sizeof (ElfW2(LIBELFBITS,Ehdr))))
463 {
464 __libelf_seterrno (ELF_E_WRITE_ERROR);
465 return 1;
466 }
467
468 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY;
469 }
470
471 /* If the type sizes should be different at some time we have to
472 rewrite this code. */
473 assert (sizeof (ElfW2(LIBELFBITS,Phdr))
474 == elf_typesize (LIBELFBITS, ELF_T_PHDR, 1));
475
476 /* Write out the program header table. */
477 if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL
478 && ((elf->state.ELFW(elf,LIBELFBITS).phdr_flags | elf->flags)
479 & ELF_F_DIRTY))
480 {
481 ElfW2(LIBELFBITS,Phdr) *tmp_phdr = NULL;
482 ElfW2(LIBELFBITS,Phdr) *out_phdr = elf->state.ELFW(elf,LIBELFBITS).phdr;
483
484 /* Maybe the user wants a gap between the ELF header and the program
485 header. */
486 if (ehdr->e_phoff > ehdr->e_ehsize
487 && unlikely (fill (elf->fildes, ehdr->e_ehsize,
488 ehdr->e_phoff - ehdr->e_ehsize, fillbuf, &filled)
489 != 0))
490 return 1;
491
492 if (unlikely (change_bo))
493 {
494 /* Today there is only one version of the ELF header. */
495#if EV_NUM != 2
Ulrich Drepper697d8d22006-04-04 21:07:28 +0000496 xfct_t fctp;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000497 fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR];
498#else
499# undef fctp
500# define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR]
501#endif
502
503 /* Allocate sufficient memory. */
504 tmp_phdr = (ElfW2(LIBELFBITS,Phdr) *)
505 malloc (sizeof (ElfW2(LIBELFBITS,Phdr)) * ehdr->e_phnum);
506 if (tmp_phdr == NULL)
507 {
508 __libelf_seterrno (ELF_E_NOMEM);
509 return 1;
510 }
511
512 /* Write the converted ELF header in a temporary buffer. */
513 (*fctp) (tmp_phdr, elf->state.ELFW(elf,LIBELFBITS).phdr,
514 sizeof (ElfW2(LIBELFBITS,Phdr)) * ehdr->e_phnum, 1);
515
516 /* This is the buffer we want to write. */
517 out_phdr = tmp_phdr;
518 }
519
520 /* Write out the ELF header. */
Ulrich Drepperfbe998a2005-08-29 16:27:10 +0000521 size_t phdr_size = sizeof (ElfW2(LIBELFBITS,Phdr)) * ehdr->e_phnum;
522 if (unlikely ((size_t) pwrite_retry (elf->fildes, out_phdr,
523 phdr_size, ehdr->e_phoff)
524 != phdr_size))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000525 {
526 __libelf_seterrno (ELF_E_WRITE_ERROR);
527 return 1;
528 }
529
530 /* This is a no-op we we have not allocated any memory. */
531 free (tmp_phdr);
532
533 elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY;
534 }
535
536 /* From now on we have to keep track of the last position to eventually
537 fill the gaps with the prescribed fill byte. */
538 off_t last_offset;
539 if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL)
540 last_offset = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
541 else
542 last_offset = (ehdr->e_phoff
543 + sizeof (ElfW2(LIBELFBITS,Phdr)) * ehdr->e_phnum);
544
545 /* Write all the sections. Well, only those which are modified. */
546 if (shnum > 0)
547 {
548 off_t shdr_offset = elf->start_offset + ehdr->e_shoff;
549#if EV_NUM != 2
550 xfct_t shdr_fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR];
551#else
552# undef shdr_fctp
553# define shdr_fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR]
554#endif
555
556 ElfW2(LIBELFBITS,Shdr) *shdr_data;
557 if (change_bo || elf->state.ELFW(elf,LIBELFBITS).shdr == NULL)
558 shdr_data = (ElfW2(LIBELFBITS,Shdr) *)
559 alloca (shnum * sizeof (ElfW2(LIBELFBITS,Shdr)));
560 else
561 shdr_data = elf->state.ELFW(elf,LIBELFBITS).shdr;
562 int shdr_flags = elf->flags;
563
564 /* Get all sections into the array and sort them. */
565 Elf_ScnList *list = &elf->state.ELFW(elf,LIBELFBITS).scns;
566 Elf_Scn **scns = (Elf_Scn **) alloca (shnum * sizeof (Elf_Scn *));
567 sort_sections (scns, list);
568
569 for (size_t cnt = 0; cnt < shnum; ++cnt)
570 {
571 Elf_Scn *scn = scns[cnt];
572
573 ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
574
575 off_t scn_start = elf->start_offset + shdr->sh_offset;
576 Elf_Data_List *dl = &scn->data_list;
577
578 if (shdr->sh_type != SHT_NOBITS && scn->data_list_rear != NULL
579 && scn->index != 0)
580 do
581 {
582 if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY)
583 {
584 char tmpbuf[MAX_TMPBUF];
585 void *buf = dl->data.d.d_buf;
586
587 if (scn_start + dl->data.d.d_off != last_offset)
588 {
589 assert (last_offset < scn_start + dl->data.d.d_off);
590
591 if (unlikely (fill (elf->fildes, last_offset,
592 (scn_start + dl->data.d.d_off)
593 - last_offset, fillbuf,
594 &filled) != 0))
595 return 1;
596
597 last_offset = scn_start + dl->data.d.d_off;
598 }
599
600 if (unlikely (change_bo))
601 {
602#if EV_NUM != 2
Ulrich Drepper697d8d22006-04-04 21:07:28 +0000603 xfct_t fctp;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000604 fctp = __elf_xfctstom[__libelf_version - 1][dl->data.d.d_version - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type];
605#else
606# undef fctp
Ulrich Drepper697d8d22006-04-04 21:07:28 +0000607# define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type]
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000608#endif
609
610 buf = tmpbuf;
611 if (dl->data.d.d_size > MAX_TMPBUF)
612 {
613 buf = malloc (dl->data.d.d_size);
614 if (buf == NULL)
615 {
616 __libelf_seterrno (ELF_E_NOMEM);
617 return 1;
618 }
619 }
620
621 /* Do the real work. */
622 (*fctp) (buf, dl->data.d.d_buf, dl->data.d.d_size, 1);
623 }
624
Ulrich Drepperfbe998a2005-08-29 16:27:10 +0000625 ssize_t n = pwrite_retry (elf->fildes, buf,
626 dl->data.d.d_size,
627 last_offset);
628 if (unlikely ((size_t) n != dl->data.d.d_size))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000629 {
630 if (buf != dl->data.d.d_buf && buf != tmpbuf)
631 free (buf);
632
633 __libelf_seterrno (ELF_E_WRITE_ERROR);
634 return 1;
635 }
636
637 if (buf != dl->data.d.d_buf && buf != tmpbuf)
638 free (buf);
639 }
640
641 last_offset += dl->data.d.d_size;
642
643 dl->flags &= ~ELF_F_DIRTY;
644
645 dl = dl->next;
646 }
647 while (dl != NULL);
648 else if (shdr->sh_type != SHT_NOBITS && scn->index != 0)
649 last_offset = scn_start + shdr->sh_size;
650
651 /* Collect the section header table information. */
652 if (unlikely (change_bo))
653 (*shdr_fctp) (&shdr_data[scn->index],
654 scn->shdr.ELFW(e,LIBELFBITS),
655 sizeof (ElfW2(LIBELFBITS,Shdr)), 1);
656 else if (elf->state.ELFW(elf,LIBELFBITS).shdr == NULL)
657 memcpy (&shdr_data[scn->index], scn->shdr.ELFW(e,LIBELFBITS),
658 sizeof (ElfW2(LIBELFBITS,Shdr)));
659
660 shdr_flags |= scn->shdr_flags;
661 scn->shdr_flags &= ~ELF_F_DIRTY;
662 }
663
664 /* Fill the gap between last section and section header table if
665 necessary. */
666 if ((elf->flags & ELF_F_DIRTY) && last_offset < shdr_offset
667 && unlikely (fill (elf->fildes, last_offset,
668 shdr_offset - last_offset,
669 fillbuf, &filled) != 0))
670 return 1;
671
672 /* Write out the section header table. */
673 if (shdr_flags & ELF_F_DIRTY
Ulrich Drepperfbe998a2005-08-29 16:27:10 +0000674 && unlikely ((size_t) pwrite_retry (elf->fildes, shdr_data,
675 sizeof (ElfW2(LIBELFBITS,Shdr))
676 * shnum, shdr_offset)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000677 != sizeof (ElfW2(LIBELFBITS,Shdr)) * shnum))
678 {
679 __libelf_seterrno (ELF_E_WRITE_ERROR);
680 return 1;
681 }
682 }
683
684 /* That was the last part. Clear the overall flag. */
685 elf->flags &= ~ELF_F_DIRTY;
686
687 return 0;
688}