blob: 682536515017aedfd6c74d5aaa492aade8f16fd5 [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
Ulrich Drepper077c65f2006-07-12 19:54:51 +0000115internal_function
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000116__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 }
Ulrich Drepperf97208e2006-05-28 07:47:25 +0000242
243 /* If the file is mmaped and the original position of the
244 section in the file is lower than the new position we
245 need to save the section content since otherwise it is
246 overwritten before it can be copied. If there are
247 multiple data segments in the list only the first can be
248 from the file. */
249 if (((char *) elf->map_address + elf->start_offset
250 <= (char *) scn->data_list.data.d.d_buf)
251 && ((char *) scn->data_list.data.d.d_buf
252 < ((char *) elf->map_address + elf->start_offset
253 + elf->maximum_size))
254 && (((char *) elf->map_address + elf->start_offset
255 + scn->shdr.ELFW(e,LIBELFBITS)->sh_offset)
256 > (char *) scn->data_list.data.d.d_buf))
257 {
258 void *p = malloc (scn->data_list.data.d.d_size);
259 if (p == NULL)
260 {
261 __libelf_seterrno (ELF_E_NOMEM);
262 return -1;
263 }
264 scn->data_list.data.d.d_buf = scn->data_base
265 = memcpy (p, scn->data_list.data.d.d_buf,
266 scn->data_list.data.d.d_size);
267 }
Ulrich Drepper697d8d22006-04-04 21:07:28 +0000268 }
269
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000270 /* Iterate over all the section in the order in which they
271 appear in the output file. */
272 for (size_t cnt = 0; cnt < shnum; ++cnt)
273 {
274 Elf_Scn *scn = scns[cnt];
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000275
Ulrich Drepper697d8d22006-04-04 21:07:28 +0000276 ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000277
Ulrich Drepper697d8d22006-04-04 21:07:28 +0000278 char *scn_start = ((char *) elf->map_address
279 + elf->start_offset + shdr->sh_offset);
280 Elf_Data_List *dl = &scn->data_list;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000281
282 if (shdr->sh_type != SHT_NOBITS && scn->data_list_rear != NULL)
283 do
284 {
285 if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY)
286 {
287 if (scn_start + dl->data.d.d_off != last_position)
288 {
289 if (scn_start + dl->data.d.d_off > last_position)
290 {
291 /* This code assumes that the data blocks for
292 a section are ordered by offset. */
293 size_t written = 0;
294
295 if (last_position < shdr_start)
296 {
297 written = MIN (scn_start + dl->data.d.d_off
298 - last_position,
299 shdr_start - last_position);
300
301 memset (last_position, __libelf_fill_byte,
302 written);
303 }
304
305 if (last_position + written
306 != scn_start + dl->data.d.d_off
307 && shdr_end < scn_start + dl->data.d.d_off)
308 memset (shdr_end, __libelf_fill_byte,
309 scn_start + dl->data.d.d_off - shdr_end);
310
311 last_position = scn_start + dl->data.d.d_off;
312 }
313 }
314
315 if (unlikely (change_bo))
316 {
317#if EV_NUM != 2
Ulrich Drepper697d8d22006-04-04 21:07:28 +0000318 xfct_t fctp;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000319 fctp = __elf_xfctstom[__libelf_version - 1][dl->data.d.d_version - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type];
320#else
321# undef fctp
Ulrich Drepper697d8d22006-04-04 21:07:28 +0000322# define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type]
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000323#endif
324
325 /* Do the real work. */
326 (*fctp) (last_position, dl->data.d.d_buf,
327 dl->data.d.d_size, 1);
328
329 last_position += dl->data.d.d_size;
330 }
331 else
332 last_position = mempcpy (last_position,
333 dl->data.d.d_buf,
334 dl->data.d.d_size);
335 }
336 else
337 last_position += dl->data.d.d_size;
338
339 dl->flags &= ~ELF_F_DIRTY;
340
341 dl = dl->next;
342 }
343 while (dl != NULL);
344 else if (shdr->sh_type != SHT_NOBITS && scn->index != 0)
345 /* We have to trust the existing section header information. */
346 last_position += shdr->sh_size;
347
Ulrich Drepper697d8d22006-04-04 21:07:28 +0000348 scn->flags &= ~ELF_F_DIRTY;
349 }
350
351 /* Fill the gap between last section and section header table if
352 necessary. */
353 if ((elf->flags & ELF_F_DIRTY)
354 && last_position < ((char *) elf->map_address + elf->start_offset
355 + ehdr->e_shoff))
356 memset (last_position, __libelf_fill_byte,
357 (char *) elf->map_address + elf->start_offset + ehdr->e_shoff
358 - last_position);
359
360 /* Write the section header table entry if necessary. */
361 for (size_t cnt = 0; cnt < shnum; ++cnt)
362 {
363 Elf_Scn *scn = scns[cnt];
364
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000365 if ((scn->shdr_flags | elf->flags) & ELF_F_DIRTY)
366 {
367 if (unlikely (change_bo))
368 (*shdr_fctp) (&shdr_dest[scn->index],
369 scn->shdr.ELFW(e,LIBELFBITS),
370 sizeof (ElfW2(LIBELFBITS,Shdr)), 1);
371 else
372 memcpy (&shdr_dest[scn->index],
373 scn->shdr.ELFW(e,LIBELFBITS),
374 sizeof (ElfW2(LIBELFBITS,Shdr)));
375
Ulrich Drepper697d8d22006-04-04 21:07:28 +0000376 /* If we previously made a copy of the section header
377 entry we now have to adjust the pointer again so
378 point to new place in the mapping. */
Roland McGrathb4379722006-04-05 01:35:26 +0000379 if (!elf->state.ELFW(elf,LIBELFBITS).shdr_malloced
380 && (scn->shdr_flags & ELF_F_MALLOCED) == 0)
Ulrich Drepper697d8d22006-04-04 21:07:28 +0000381 scn->shdr.ELFW(e,LIBELFBITS) = &shdr_dest[scn->index];
382
Roland McGrathb4379722006-04-05 01:35:26 +0000383 scn->shdr_flags &= ~ELF_F_DIRTY;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000384 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000385 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000386 }
387
388 /* That was the last part. Clear the overall flag. */
389 elf->flags &= ~ELF_F_DIRTY;
390
Ulrich Drepper697d8d22006-04-04 21:07:28 +0000391 /* Make sure the content hits the disk. */
392 char *msync_start = ((char *) elf->map_address
Ulrich Drepperf97208e2006-05-28 07:47:25 +0000393 + (elf->start_offset & ~(sysconf (_SC_PAGESIZE) - 1)));
Ulrich Drepper697d8d22006-04-04 21:07:28 +0000394 char *msync_end = ((char *) elf->map_address
395 + elf->start_offset + ehdr->e_shoff
Ulrich Drepperf97208e2006-05-28 07:47:25 +0000396 + ehdr->e_shentsize * shnum);
Ulrich Drepper697d8d22006-04-04 21:07:28 +0000397 (void) msync (msync_start, msync_end - msync_start, MS_SYNC);
398
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000399 return 0;
400}
401
402
403/* Size of the buffer we use to generate the blocks of fill bytes. */
404#define FILLBUFSIZE 4096
405
406/* If we have to convert the section buffer contents we have to use
407 temporary buffer. Only buffers up to MAX_TMPBUF bytes are allocated
408 on the stack. */
409#define MAX_TMPBUF 32768
410
411
412/* Helper function to write out fill bytes. */
413static int
414fill (int fd, off_t pos, size_t len, char *fillbuf, size_t *filledp)
415{
416 size_t filled = *filledp;
417 size_t fill_len = MIN (len, FILLBUFSIZE);
418
419 if (unlikely (fill_len > filled) && filled < FILLBUFSIZE)
420 {
421 /* Initialize a few more bytes. */
422 memset (fillbuf + filled, __libelf_fill_byte, fill_len - filled);
423 *filledp = filled = fill_len;
424 }
425
426 do
427 {
428 /* This many bytes we want to write in this round. */
429 size_t n = MIN (filled, len);
430
Ulrich Drepperfbe998a2005-08-29 16:27:10 +0000431 if (unlikely ((size_t) pwrite_retry (fd, fillbuf, n, pos) != n))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000432 {
433 __libelf_seterrno (ELF_E_WRITE_ERROR);
434 return 1;
435 }
436
437 pos += n;
438 len -= n;
439 }
440 while (len > 0);
441
442 return 0;
443}
444
445
446int
Ulrich Drepper077c65f2006-07-12 19:54:51 +0000447internal_function
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000448__elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum)
449{
450 char fillbuf[FILLBUFSIZE];
451 size_t filled = 0;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000452
453 /* We need the ELF header several times. */
454 ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
455
456 /* Write out the ELF header. */
457 if ((elf->state.ELFW(elf,LIBELFBITS).ehdr_flags | elf->flags) & ELF_F_DIRTY)
458 {
459 ElfW2(LIBELFBITS,Ehdr) tmp_ehdr;
460 ElfW2(LIBELFBITS,Ehdr) *out_ehdr = ehdr;
461
462 /* If the type sizes should be different at some time we have to
463 rewrite this code. */
464 assert (sizeof (ElfW2(LIBELFBITS,Ehdr))
465 == elf_typesize (LIBELFBITS, ELF_T_EHDR, 1));
466
467 if (unlikely (change_bo))
468 {
469 /* Today there is only one version of the ELF header. */
470#if EV_NUM != 2
Ulrich Drepper697d8d22006-04-04 21:07:28 +0000471 xfct_t fctp;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000472 fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR];
473#else
474# undef fctp
475# define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR]
476#endif
477
478 /* Write the converted ELF header in a temporary buffer. */
479 (*fctp) (&tmp_ehdr, ehdr, sizeof (ElfW2(LIBELFBITS,Ehdr)), 1);
480
481 /* This is the buffer we want to write. */
482 out_ehdr = &tmp_ehdr;
483 }
484
485 /* Write out the ELF header. */
Ulrich Drepperfbe998a2005-08-29 16:27:10 +0000486 if (unlikely (pwrite_retry (elf->fildes, out_ehdr,
487 sizeof (ElfW2(LIBELFBITS,Ehdr)), 0)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000488 != sizeof (ElfW2(LIBELFBITS,Ehdr))))
489 {
490 __libelf_seterrno (ELF_E_WRITE_ERROR);
491 return 1;
492 }
493
494 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY;
495 }
496
497 /* If the type sizes should be different at some time we have to
498 rewrite this code. */
499 assert (sizeof (ElfW2(LIBELFBITS,Phdr))
500 == elf_typesize (LIBELFBITS, ELF_T_PHDR, 1));
501
502 /* Write out the program header table. */
503 if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL
504 && ((elf->state.ELFW(elf,LIBELFBITS).phdr_flags | elf->flags)
505 & ELF_F_DIRTY))
506 {
507 ElfW2(LIBELFBITS,Phdr) *tmp_phdr = NULL;
508 ElfW2(LIBELFBITS,Phdr) *out_phdr = elf->state.ELFW(elf,LIBELFBITS).phdr;
509
510 /* Maybe the user wants a gap between the ELF header and the program
511 header. */
512 if (ehdr->e_phoff > ehdr->e_ehsize
513 && unlikely (fill (elf->fildes, ehdr->e_ehsize,
514 ehdr->e_phoff - ehdr->e_ehsize, fillbuf, &filled)
515 != 0))
516 return 1;
517
518 if (unlikely (change_bo))
519 {
520 /* Today there is only one version of the ELF header. */
521#if EV_NUM != 2
Ulrich Drepper697d8d22006-04-04 21:07:28 +0000522 xfct_t fctp;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000523 fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR];
524#else
525# undef fctp
526# define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR]
527#endif
528
529 /* Allocate sufficient memory. */
530 tmp_phdr = (ElfW2(LIBELFBITS,Phdr) *)
531 malloc (sizeof (ElfW2(LIBELFBITS,Phdr)) * ehdr->e_phnum);
532 if (tmp_phdr == NULL)
533 {
534 __libelf_seterrno (ELF_E_NOMEM);
535 return 1;
536 }
537
538 /* Write the converted ELF header in a temporary buffer. */
539 (*fctp) (tmp_phdr, elf->state.ELFW(elf,LIBELFBITS).phdr,
540 sizeof (ElfW2(LIBELFBITS,Phdr)) * ehdr->e_phnum, 1);
541
542 /* This is the buffer we want to write. */
543 out_phdr = tmp_phdr;
544 }
545
546 /* Write out the ELF header. */
Ulrich Drepperfbe998a2005-08-29 16:27:10 +0000547 size_t phdr_size = sizeof (ElfW2(LIBELFBITS,Phdr)) * ehdr->e_phnum;
548 if (unlikely ((size_t) pwrite_retry (elf->fildes, out_phdr,
549 phdr_size, ehdr->e_phoff)
550 != phdr_size))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000551 {
552 __libelf_seterrno (ELF_E_WRITE_ERROR);
553 return 1;
554 }
555
556 /* This is a no-op we we have not allocated any memory. */
557 free (tmp_phdr);
558
559 elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY;
560 }
561
562 /* From now on we have to keep track of the last position to eventually
563 fill the gaps with the prescribed fill byte. */
564 off_t last_offset;
565 if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL)
566 last_offset = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
567 else
568 last_offset = (ehdr->e_phoff
569 + sizeof (ElfW2(LIBELFBITS,Phdr)) * ehdr->e_phnum);
570
571 /* Write all the sections. Well, only those which are modified. */
572 if (shnum > 0)
573 {
574 off_t shdr_offset = elf->start_offset + ehdr->e_shoff;
575#if EV_NUM != 2
576 xfct_t shdr_fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR];
577#else
578# undef shdr_fctp
579# define shdr_fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR]
580#endif
581
582 ElfW2(LIBELFBITS,Shdr) *shdr_data;
583 if (change_bo || elf->state.ELFW(elf,LIBELFBITS).shdr == NULL)
584 shdr_data = (ElfW2(LIBELFBITS,Shdr) *)
585 alloca (shnum * sizeof (ElfW2(LIBELFBITS,Shdr)));
586 else
587 shdr_data = elf->state.ELFW(elf,LIBELFBITS).shdr;
588 int shdr_flags = elf->flags;
589
590 /* Get all sections into the array and sort them. */
591 Elf_ScnList *list = &elf->state.ELFW(elf,LIBELFBITS).scns;
592 Elf_Scn **scns = (Elf_Scn **) alloca (shnum * sizeof (Elf_Scn *));
593 sort_sections (scns, list);
594
595 for (size_t cnt = 0; cnt < shnum; ++cnt)
596 {
597 Elf_Scn *scn = scns[cnt];
598
599 ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
600
601 off_t scn_start = elf->start_offset + shdr->sh_offset;
602 Elf_Data_List *dl = &scn->data_list;
603
604 if (shdr->sh_type != SHT_NOBITS && scn->data_list_rear != NULL
605 && scn->index != 0)
606 do
607 {
608 if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY)
609 {
610 char tmpbuf[MAX_TMPBUF];
611 void *buf = dl->data.d.d_buf;
612
613 if (scn_start + dl->data.d.d_off != last_offset)
614 {
615 assert (last_offset < scn_start + dl->data.d.d_off);
616
617 if (unlikely (fill (elf->fildes, last_offset,
618 (scn_start + dl->data.d.d_off)
619 - last_offset, fillbuf,
620 &filled) != 0))
621 return 1;
622
623 last_offset = scn_start + dl->data.d.d_off;
624 }
625
626 if (unlikely (change_bo))
627 {
628#if EV_NUM != 2
Ulrich Drepper697d8d22006-04-04 21:07:28 +0000629 xfct_t fctp;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000630 fctp = __elf_xfctstom[__libelf_version - 1][dl->data.d.d_version - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type];
631#else
632# undef fctp
Ulrich Drepper697d8d22006-04-04 21:07:28 +0000633# define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type]
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000634#endif
635
636 buf = tmpbuf;
637 if (dl->data.d.d_size > MAX_TMPBUF)
638 {
639 buf = malloc (dl->data.d.d_size);
640 if (buf == NULL)
641 {
642 __libelf_seterrno (ELF_E_NOMEM);
643 return 1;
644 }
645 }
646
647 /* Do the real work. */
648 (*fctp) (buf, dl->data.d.d_buf, dl->data.d.d_size, 1);
649 }
650
Ulrich Drepperfbe998a2005-08-29 16:27:10 +0000651 ssize_t n = pwrite_retry (elf->fildes, buf,
652 dl->data.d.d_size,
653 last_offset);
654 if (unlikely ((size_t) n != dl->data.d.d_size))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000655 {
656 if (buf != dl->data.d.d_buf && buf != tmpbuf)
657 free (buf);
658
659 __libelf_seterrno (ELF_E_WRITE_ERROR);
660 return 1;
661 }
662
663 if (buf != dl->data.d.d_buf && buf != tmpbuf)
664 free (buf);
665 }
666
667 last_offset += dl->data.d.d_size;
668
669 dl->flags &= ~ELF_F_DIRTY;
670
671 dl = dl->next;
672 }
673 while (dl != NULL);
674 else if (shdr->sh_type != SHT_NOBITS && scn->index != 0)
675 last_offset = scn_start + shdr->sh_size;
676
677 /* Collect the section header table information. */
678 if (unlikely (change_bo))
679 (*shdr_fctp) (&shdr_data[scn->index],
680 scn->shdr.ELFW(e,LIBELFBITS),
681 sizeof (ElfW2(LIBELFBITS,Shdr)), 1);
682 else if (elf->state.ELFW(elf,LIBELFBITS).shdr == NULL)
683 memcpy (&shdr_data[scn->index], scn->shdr.ELFW(e,LIBELFBITS),
684 sizeof (ElfW2(LIBELFBITS,Shdr)));
685
686 shdr_flags |= scn->shdr_flags;
687 scn->shdr_flags &= ~ELF_F_DIRTY;
688 }
689
690 /* Fill the gap between last section and section header table if
691 necessary. */
692 if ((elf->flags & ELF_F_DIRTY) && last_offset < shdr_offset
693 && unlikely (fill (elf->fildes, last_offset,
694 shdr_offset - last_offset,
695 fillbuf, &filled) != 0))
696 return 1;
697
698 /* Write out the section header table. */
699 if (shdr_flags & ELF_F_DIRTY
Ulrich Drepperfbe998a2005-08-29 16:27:10 +0000700 && unlikely ((size_t) pwrite_retry (elf->fildes, shdr_data,
701 sizeof (ElfW2(LIBELFBITS,Shdr))
702 * shnum, shdr_offset)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000703 != sizeof (ElfW2(LIBELFBITS,Shdr)) * shnum))
704 {
705 __libelf_seterrno (ELF_E_WRITE_ERROR);
706 return 1;
707 }
708 }
709
710 /* That was the last part. Clear the overall flag. */
711 elf->flags &= ~ELF_F_DIRTY;
712
713 return 0;
714}