1*7304104dSAndroid Build Coastguard Worker /* Write changed data structures.
2*7304104dSAndroid Build Coastguard Worker Copyright (C) 2000-2010, 2014, 2015, 2016, 2018 Red Hat, Inc.
3*7304104dSAndroid Build Coastguard Worker This file is part of elfutils.
4*7304104dSAndroid Build Coastguard Worker Written by Ulrich Drepper <[email protected]>, 2000.
5*7304104dSAndroid Build Coastguard Worker
6*7304104dSAndroid Build Coastguard Worker This file is free software; you can redistribute it and/or modify
7*7304104dSAndroid Build Coastguard Worker it under the terms of either
8*7304104dSAndroid Build Coastguard Worker
9*7304104dSAndroid Build Coastguard Worker * the GNU Lesser General Public License as published by the Free
10*7304104dSAndroid Build Coastguard Worker Software Foundation; either version 3 of the License, or (at
11*7304104dSAndroid Build Coastguard Worker your option) any later version
12*7304104dSAndroid Build Coastguard Worker
13*7304104dSAndroid Build Coastguard Worker or
14*7304104dSAndroid Build Coastguard Worker
15*7304104dSAndroid Build Coastguard Worker * the GNU General Public License as published by the Free
16*7304104dSAndroid Build Coastguard Worker Software Foundation; either version 2 of the License, or (at
17*7304104dSAndroid Build Coastguard Worker your option) any later version
18*7304104dSAndroid Build Coastguard Worker
19*7304104dSAndroid Build Coastguard Worker or both in parallel, as here.
20*7304104dSAndroid Build Coastguard Worker
21*7304104dSAndroid Build Coastguard Worker elfutils is distributed in the hope that it will be useful, but
22*7304104dSAndroid Build Coastguard Worker WITHOUT ANY WARRANTY; without even the implied warranty of
23*7304104dSAndroid Build Coastguard Worker MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24*7304104dSAndroid Build Coastguard Worker General Public License for more details.
25*7304104dSAndroid Build Coastguard Worker
26*7304104dSAndroid Build Coastguard Worker You should have received copies of the GNU General Public License and
27*7304104dSAndroid Build Coastguard Worker the GNU Lesser General Public License along with this program. If
28*7304104dSAndroid Build Coastguard Worker not, see <http://www.gnu.org/licenses/>. */
29*7304104dSAndroid Build Coastguard Worker
30*7304104dSAndroid Build Coastguard Worker #ifdef HAVE_CONFIG_H
31*7304104dSAndroid Build Coastguard Worker # include <config.h>
32*7304104dSAndroid Build Coastguard Worker #endif
33*7304104dSAndroid Build Coastguard Worker
34*7304104dSAndroid Build Coastguard Worker #include <assert.h>
35*7304104dSAndroid Build Coastguard Worker #include <errno.h>
36*7304104dSAndroid Build Coastguard Worker #include <libelf.h>
37*7304104dSAndroid Build Coastguard Worker #include <stdbool.h>
38*7304104dSAndroid Build Coastguard Worker #include <stdlib.h>
39*7304104dSAndroid Build Coastguard Worker #include <string.h>
40*7304104dSAndroid Build Coastguard Worker
41*7304104dSAndroid Build Coastguard Worker #include "libelfP.h"
42*7304104dSAndroid Build Coastguard Worker
43*7304104dSAndroid Build Coastguard Worker
44*7304104dSAndroid Build Coastguard Worker #ifndef LIBELFBITS
45*7304104dSAndroid Build Coastguard Worker # define LIBELFBITS 32
46*7304104dSAndroid Build Coastguard Worker #endif
47*7304104dSAndroid Build Coastguard Worker
48*7304104dSAndroid Build Coastguard Worker
49*7304104dSAndroid Build Coastguard Worker static int
compare_sections(const void * a,const void * b)50*7304104dSAndroid Build Coastguard Worker compare_sections (const void *a, const void *b)
51*7304104dSAndroid Build Coastguard Worker {
52*7304104dSAndroid Build Coastguard Worker const Elf_Scn **scna = (const Elf_Scn **) a;
53*7304104dSAndroid Build Coastguard Worker const Elf_Scn **scnb = (const Elf_Scn **) b;
54*7304104dSAndroid Build Coastguard Worker
55*7304104dSAndroid Build Coastguard Worker if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_offset
56*7304104dSAndroid Build Coastguard Worker < (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_offset)
57*7304104dSAndroid Build Coastguard Worker return -1;
58*7304104dSAndroid Build Coastguard Worker
59*7304104dSAndroid Build Coastguard Worker if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_offset
60*7304104dSAndroid Build Coastguard Worker > (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_offset)
61*7304104dSAndroid Build Coastguard Worker return 1;
62*7304104dSAndroid Build Coastguard Worker
63*7304104dSAndroid Build Coastguard Worker if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_size
64*7304104dSAndroid Build Coastguard Worker < (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_size)
65*7304104dSAndroid Build Coastguard Worker return -1;
66*7304104dSAndroid Build Coastguard Worker
67*7304104dSAndroid Build Coastguard Worker if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_size
68*7304104dSAndroid Build Coastguard Worker > (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_size)
69*7304104dSAndroid Build Coastguard Worker return 1;
70*7304104dSAndroid Build Coastguard Worker
71*7304104dSAndroid Build Coastguard Worker if ((*scna)->index < (*scnb)->index)
72*7304104dSAndroid Build Coastguard Worker return -1;
73*7304104dSAndroid Build Coastguard Worker
74*7304104dSAndroid Build Coastguard Worker if ((*scna)->index > (*scnb)->index)
75*7304104dSAndroid Build Coastguard Worker return 1;
76*7304104dSAndroid Build Coastguard Worker
77*7304104dSAndroid Build Coastguard Worker return 0;
78*7304104dSAndroid Build Coastguard Worker }
79*7304104dSAndroid Build Coastguard Worker
80*7304104dSAndroid Build Coastguard Worker
81*7304104dSAndroid Build Coastguard Worker /* Insert the sections in the list into the provided array and sort
82*7304104dSAndroid Build Coastguard Worker them according to their start offsets. For sections with equal
83*7304104dSAndroid Build Coastguard Worker start offsets, the size is used; for sections with equal start
84*7304104dSAndroid Build Coastguard Worker offsets and sizes, the section index is used. Sorting by size
85*7304104dSAndroid Build Coastguard Worker ensures that zero-length sections are processed first, which
86*7304104dSAndroid Build Coastguard Worker is what we want since they do not advance our file writing position. */
87*7304104dSAndroid Build Coastguard Worker static void
sort_sections(Elf_Scn ** scns,Elf_ScnList * list)88*7304104dSAndroid Build Coastguard Worker sort_sections (Elf_Scn **scns, Elf_ScnList *list)
89*7304104dSAndroid Build Coastguard Worker {
90*7304104dSAndroid Build Coastguard Worker Elf_Scn **scnp = scns;
91*7304104dSAndroid Build Coastguard Worker do
92*7304104dSAndroid Build Coastguard Worker for (size_t cnt = 0; cnt < list->cnt; ++cnt)
93*7304104dSAndroid Build Coastguard Worker *scnp++ = &list->data[cnt];
94*7304104dSAndroid Build Coastguard Worker while ((list = list->next) != NULL);
95*7304104dSAndroid Build Coastguard Worker
96*7304104dSAndroid Build Coastguard Worker qsort (scns, scnp - scns, sizeof (*scns), compare_sections);
97*7304104dSAndroid Build Coastguard Worker }
98*7304104dSAndroid Build Coastguard Worker
99*7304104dSAndroid Build Coastguard Worker
100*7304104dSAndroid Build Coastguard Worker static inline void
fill_mmap(size_t offset,char * last_position,char * scn_start,char * const shdr_start,char * const shdr_end)101*7304104dSAndroid Build Coastguard Worker fill_mmap (size_t offset, char *last_position, char *scn_start,
102*7304104dSAndroid Build Coastguard Worker char *const shdr_start, char *const shdr_end)
103*7304104dSAndroid Build Coastguard Worker {
104*7304104dSAndroid Build Coastguard Worker size_t written = 0;
105*7304104dSAndroid Build Coastguard Worker
106*7304104dSAndroid Build Coastguard Worker if (last_position < shdr_start)
107*7304104dSAndroid Build Coastguard Worker {
108*7304104dSAndroid Build Coastguard Worker written = MIN (scn_start + offset - last_position,
109*7304104dSAndroid Build Coastguard Worker shdr_start - last_position);
110*7304104dSAndroid Build Coastguard Worker
111*7304104dSAndroid Build Coastguard Worker memset (last_position, __libelf_fill_byte, written);
112*7304104dSAndroid Build Coastguard Worker }
113*7304104dSAndroid Build Coastguard Worker
114*7304104dSAndroid Build Coastguard Worker if (last_position + written != scn_start + offset
115*7304104dSAndroid Build Coastguard Worker && shdr_end < scn_start + offset)
116*7304104dSAndroid Build Coastguard Worker {
117*7304104dSAndroid Build Coastguard Worker char *fill_start = MAX (shdr_end, scn_start);
118*7304104dSAndroid Build Coastguard Worker memset (fill_start, __libelf_fill_byte,
119*7304104dSAndroid Build Coastguard Worker scn_start + offset - fill_start);
120*7304104dSAndroid Build Coastguard Worker }
121*7304104dSAndroid Build Coastguard Worker }
122*7304104dSAndroid Build Coastguard Worker
123*7304104dSAndroid Build Coastguard Worker int
124*7304104dSAndroid Build Coastguard Worker internal_function
__elfw2(LIBELFBITS,updatemmap)125*7304104dSAndroid Build Coastguard Worker __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum)
126*7304104dSAndroid Build Coastguard Worker {
127*7304104dSAndroid Build Coastguard Worker bool previous_scn_changed = false;
128*7304104dSAndroid Build Coastguard Worker
129*7304104dSAndroid Build Coastguard Worker /* We need the ELF header several times. */
130*7304104dSAndroid Build Coastguard Worker ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
131*7304104dSAndroid Build Coastguard Worker
132*7304104dSAndroid Build Coastguard Worker /* Write out the ELF header. */
133*7304104dSAndroid Build Coastguard Worker if ((elf->state.ELFW(elf,LIBELFBITS).ehdr_flags | elf->flags) & ELF_F_DIRTY)
134*7304104dSAndroid Build Coastguard Worker {
135*7304104dSAndroid Build Coastguard Worker /* If the type sizes should be different at some time we have to
136*7304104dSAndroid Build Coastguard Worker rewrite this code. */
137*7304104dSAndroid Build Coastguard Worker assert (sizeof (ElfW2(LIBELFBITS,Ehdr))
138*7304104dSAndroid Build Coastguard Worker == elf_typesize (LIBELFBITS, ELF_T_EHDR, 1));
139*7304104dSAndroid Build Coastguard Worker
140*7304104dSAndroid Build Coastguard Worker if (unlikely (change_bo))
141*7304104dSAndroid Build Coastguard Worker {
142*7304104dSAndroid Build Coastguard Worker /* Today there is only one version of the ELF header. */
143*7304104dSAndroid Build Coastguard Worker #undef fctp
144*7304104dSAndroid Build Coastguard Worker #define fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR]
145*7304104dSAndroid Build Coastguard Worker
146*7304104dSAndroid Build Coastguard Worker /* Do the real work. */
147*7304104dSAndroid Build Coastguard Worker (*fctp) ((char *) elf->map_address + elf->start_offset, ehdr,
148*7304104dSAndroid Build Coastguard Worker sizeof (ElfW2(LIBELFBITS,Ehdr)), 1);
149*7304104dSAndroid Build Coastguard Worker }
150*7304104dSAndroid Build Coastguard Worker else if (elf->map_address + elf->start_offset != ehdr)
151*7304104dSAndroid Build Coastguard Worker memcpy (elf->map_address + elf->start_offset, ehdr,
152*7304104dSAndroid Build Coastguard Worker sizeof (ElfW2(LIBELFBITS,Ehdr)));
153*7304104dSAndroid Build Coastguard Worker
154*7304104dSAndroid Build Coastguard Worker elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY;
155*7304104dSAndroid Build Coastguard Worker
156*7304104dSAndroid Build Coastguard Worker /* We start writing sections after the ELF header only if there is
157*7304104dSAndroid Build Coastguard Worker no program header. */
158*7304104dSAndroid Build Coastguard Worker previous_scn_changed = elf->state.ELFW(elf,LIBELFBITS).phdr == NULL;
159*7304104dSAndroid Build Coastguard Worker }
160*7304104dSAndroid Build Coastguard Worker
161*7304104dSAndroid Build Coastguard Worker size_t phnum;
162*7304104dSAndroid Build Coastguard Worker if (unlikely (__elf_getphdrnum_rdlock (elf, &phnum) != 0))
163*7304104dSAndroid Build Coastguard Worker return -1;
164*7304104dSAndroid Build Coastguard Worker
165*7304104dSAndroid Build Coastguard Worker /* Write out the program header table. */
166*7304104dSAndroid Build Coastguard Worker if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL
167*7304104dSAndroid Build Coastguard Worker && ((elf->state.ELFW(elf,LIBELFBITS).phdr_flags | elf->flags)
168*7304104dSAndroid Build Coastguard Worker & ELF_F_DIRTY))
169*7304104dSAndroid Build Coastguard Worker {
170*7304104dSAndroid Build Coastguard Worker /* If the type sizes should be different at some time we have to
171*7304104dSAndroid Build Coastguard Worker rewrite this code. */
172*7304104dSAndroid Build Coastguard Worker assert (sizeof (ElfW2(LIBELFBITS,Phdr))
173*7304104dSAndroid Build Coastguard Worker == elf_typesize (LIBELFBITS, ELF_T_PHDR, 1));
174*7304104dSAndroid Build Coastguard Worker
175*7304104dSAndroid Build Coastguard Worker /* Maybe the user wants a gap between the ELF header and the program
176*7304104dSAndroid Build Coastguard Worker header. */
177*7304104dSAndroid Build Coastguard Worker if (ehdr->e_phoff > ehdr->e_ehsize)
178*7304104dSAndroid Build Coastguard Worker memset (elf->map_address + elf->start_offset + ehdr->e_ehsize,
179*7304104dSAndroid Build Coastguard Worker __libelf_fill_byte, ehdr->e_phoff - ehdr->e_ehsize);
180*7304104dSAndroid Build Coastguard Worker
181*7304104dSAndroid Build Coastguard Worker if (unlikely (change_bo))
182*7304104dSAndroid Build Coastguard Worker {
183*7304104dSAndroid Build Coastguard Worker /* Today there is only one version of the ELF header. */
184*7304104dSAndroid Build Coastguard Worker #undef fctp
185*7304104dSAndroid Build Coastguard Worker #define fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR]
186*7304104dSAndroid Build Coastguard Worker
187*7304104dSAndroid Build Coastguard Worker /* Do the real work. */
188*7304104dSAndroid Build Coastguard Worker (*fctp) (elf->map_address + elf->start_offset + ehdr->e_phoff,
189*7304104dSAndroid Build Coastguard Worker elf->state.ELFW(elf,LIBELFBITS).phdr,
190*7304104dSAndroid Build Coastguard Worker sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum, 1);
191*7304104dSAndroid Build Coastguard Worker }
192*7304104dSAndroid Build Coastguard Worker else
193*7304104dSAndroid Build Coastguard Worker memmove (elf->map_address + elf->start_offset + ehdr->e_phoff,
194*7304104dSAndroid Build Coastguard Worker elf->state.ELFW(elf,LIBELFBITS).phdr,
195*7304104dSAndroid Build Coastguard Worker sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum);
196*7304104dSAndroid Build Coastguard Worker
197*7304104dSAndroid Build Coastguard Worker elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY;
198*7304104dSAndroid Build Coastguard Worker
199*7304104dSAndroid Build Coastguard Worker /* We modified the program header. Maybe this created a gap so
200*7304104dSAndroid Build Coastguard Worker we have to write fill bytes, if necessary. */
201*7304104dSAndroid Build Coastguard Worker previous_scn_changed = true;
202*7304104dSAndroid Build Coastguard Worker }
203*7304104dSAndroid Build Coastguard Worker
204*7304104dSAndroid Build Coastguard Worker /* From now on we have to keep track of the last position to eventually
205*7304104dSAndroid Build Coastguard Worker fill the gaps with the prescribed fill byte. */
206*7304104dSAndroid Build Coastguard Worker char *last_position = ((char *) elf->map_address + elf->start_offset
207*7304104dSAndroid Build Coastguard Worker + MAX (elf_typesize (LIBELFBITS, ELF_T_EHDR, 1),
208*7304104dSAndroid Build Coastguard Worker ehdr->e_phoff)
209*7304104dSAndroid Build Coastguard Worker + elf_typesize (LIBELFBITS, ELF_T_PHDR, phnum));
210*7304104dSAndroid Build Coastguard Worker
211*7304104dSAndroid Build Coastguard Worker /* Write all the sections. Well, only those which are modified. */
212*7304104dSAndroid Build Coastguard Worker if (shnum > 0)
213*7304104dSAndroid Build Coastguard Worker {
214*7304104dSAndroid Build Coastguard Worker if (unlikely (shnum > SIZE_MAX / sizeof (Elf_Scn *)))
215*7304104dSAndroid Build Coastguard Worker return 1;
216*7304104dSAndroid Build Coastguard Worker
217*7304104dSAndroid Build Coastguard Worker Elf_ScnList *list = &elf->state.ELFW(elf,LIBELFBITS).scns;
218*7304104dSAndroid Build Coastguard Worker Elf_Scn **scns = malloc (shnum * sizeof (Elf_Scn *));
219*7304104dSAndroid Build Coastguard Worker if (unlikely (scns == NULL))
220*7304104dSAndroid Build Coastguard Worker {
221*7304104dSAndroid Build Coastguard Worker __libelf_seterrno (ELF_E_NOMEM);
222*7304104dSAndroid Build Coastguard Worker return -1;
223*7304104dSAndroid Build Coastguard Worker }
224*7304104dSAndroid Build Coastguard Worker char *const shdr_start = ((char *) elf->map_address + elf->start_offset
225*7304104dSAndroid Build Coastguard Worker + ehdr->e_shoff);
226*7304104dSAndroid Build Coastguard Worker char *const shdr_end = shdr_start + shnum * ehdr->e_shentsize;
227*7304104dSAndroid Build Coastguard Worker
228*7304104dSAndroid Build Coastguard Worker #undef shdr_fctp
229*7304104dSAndroid Build Coastguard Worker #define shdr_fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR]
230*7304104dSAndroid Build Coastguard Worker #define shdr_dest ((ElfW2(LIBELFBITS,Shdr) *) shdr_start)
231*7304104dSAndroid Build Coastguard Worker
232*7304104dSAndroid Build Coastguard Worker /* Get all sections into the array and sort them. */
233*7304104dSAndroid Build Coastguard Worker sort_sections (scns, list);
234*7304104dSAndroid Build Coastguard Worker
235*7304104dSAndroid Build Coastguard Worker /* We possibly have to copy the section header data because moving
236*7304104dSAndroid Build Coastguard Worker the sections might overwrite the data. */
237*7304104dSAndroid Build Coastguard Worker for (size_t cnt = 0; cnt < shnum; ++cnt)
238*7304104dSAndroid Build Coastguard Worker {
239*7304104dSAndroid Build Coastguard Worker Elf_Scn *scn = scns[cnt];
240*7304104dSAndroid Build Coastguard Worker
241*7304104dSAndroid Build Coastguard Worker if (!elf->state.ELFW(elf,LIBELFBITS).shdr_malloced
242*7304104dSAndroid Build Coastguard Worker && (scn->shdr_flags & ELF_F_MALLOCED) == 0
243*7304104dSAndroid Build Coastguard Worker && scn->shdr.ELFW(e,LIBELFBITS) != &shdr_dest[scn->index])
244*7304104dSAndroid Build Coastguard Worker {
245*7304104dSAndroid Build Coastguard Worker assert ((char *) elf->map_address + elf->start_offset
246*7304104dSAndroid Build Coastguard Worker < (char *) scn->shdr.ELFW(e,LIBELFBITS));
247*7304104dSAndroid Build Coastguard Worker assert ((char *) scn->shdr.ELFW(e,LIBELFBITS)
248*7304104dSAndroid Build Coastguard Worker < ((char *) elf->map_address + elf->start_offset
249*7304104dSAndroid Build Coastguard Worker + elf->maximum_size));
250*7304104dSAndroid Build Coastguard Worker
251*7304104dSAndroid Build Coastguard Worker void *p = malloc (sizeof (ElfW2(LIBELFBITS,Shdr)));
252*7304104dSAndroid Build Coastguard Worker if (unlikely (p == NULL))
253*7304104dSAndroid Build Coastguard Worker {
254*7304104dSAndroid Build Coastguard Worker free (scns);
255*7304104dSAndroid Build Coastguard Worker __libelf_seterrno (ELF_E_NOMEM);
256*7304104dSAndroid Build Coastguard Worker return -1;
257*7304104dSAndroid Build Coastguard Worker }
258*7304104dSAndroid Build Coastguard Worker scn->shdr.ELFW(e,LIBELFBITS)
259*7304104dSAndroid Build Coastguard Worker = memcpy (p, scn->shdr.ELFW(e,LIBELFBITS),
260*7304104dSAndroid Build Coastguard Worker sizeof (ElfW2(LIBELFBITS,Shdr)));
261*7304104dSAndroid Build Coastguard Worker }
262*7304104dSAndroid Build Coastguard Worker
263*7304104dSAndroid Build Coastguard Worker /* If the file is mmaped and the original position of the
264*7304104dSAndroid Build Coastguard Worker section in the file is lower than the new position we
265*7304104dSAndroid Build Coastguard Worker need to save the section content since otherwise it is
266*7304104dSAndroid Build Coastguard Worker overwritten before it can be copied. If there are
267*7304104dSAndroid Build Coastguard Worker multiple data segments in the list only the first can be
268*7304104dSAndroid Build Coastguard Worker from the file. */
269*7304104dSAndroid Build Coastguard Worker if (((char *) elf->map_address + elf->start_offset
270*7304104dSAndroid Build Coastguard Worker <= (char *) scn->data_list.data.d.d_buf)
271*7304104dSAndroid Build Coastguard Worker && ((char *) scn->data_list.data.d.d_buf
272*7304104dSAndroid Build Coastguard Worker < ((char *) elf->map_address + elf->start_offset
273*7304104dSAndroid Build Coastguard Worker + elf->maximum_size))
274*7304104dSAndroid Build Coastguard Worker && (((char *) elf->map_address + elf->start_offset
275*7304104dSAndroid Build Coastguard Worker + scn->shdr.ELFW(e,LIBELFBITS)->sh_offset)
276*7304104dSAndroid Build Coastguard Worker > (char *) scn->data_list.data.d.d_buf))
277*7304104dSAndroid Build Coastguard Worker {
278*7304104dSAndroid Build Coastguard Worker void *p = malloc (scn->data_list.data.d.d_size);
279*7304104dSAndroid Build Coastguard Worker if (unlikely (p == NULL))
280*7304104dSAndroid Build Coastguard Worker {
281*7304104dSAndroid Build Coastguard Worker free (scns);
282*7304104dSAndroid Build Coastguard Worker __libelf_seterrno (ELF_E_NOMEM);
283*7304104dSAndroid Build Coastguard Worker return -1;
284*7304104dSAndroid Build Coastguard Worker }
285*7304104dSAndroid Build Coastguard Worker scn->data_list.data.d.d_buf = scn->data_base
286*7304104dSAndroid Build Coastguard Worker = memcpy (p, scn->data_list.data.d.d_buf,
287*7304104dSAndroid Build Coastguard Worker scn->data_list.data.d.d_size);
288*7304104dSAndroid Build Coastguard Worker }
289*7304104dSAndroid Build Coastguard Worker }
290*7304104dSAndroid Build Coastguard Worker
291*7304104dSAndroid Build Coastguard Worker /* Iterate over all the section in the order in which they
292*7304104dSAndroid Build Coastguard Worker appear in the output file. */
293*7304104dSAndroid Build Coastguard Worker for (size_t cnt = 0; cnt < shnum; ++cnt)
294*7304104dSAndroid Build Coastguard Worker {
295*7304104dSAndroid Build Coastguard Worker Elf_Scn *scn = scns[cnt];
296*7304104dSAndroid Build Coastguard Worker if (scn->index == 0)
297*7304104dSAndroid Build Coastguard Worker {
298*7304104dSAndroid Build Coastguard Worker /* The dummy section header entry. It should not be
299*7304104dSAndroid Build Coastguard Worker possible to mark this "section" as dirty. */
300*7304104dSAndroid Build Coastguard Worker assert ((scn->flags & ELF_F_DIRTY) == 0);
301*7304104dSAndroid Build Coastguard Worker continue;
302*7304104dSAndroid Build Coastguard Worker }
303*7304104dSAndroid Build Coastguard Worker
304*7304104dSAndroid Build Coastguard Worker ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
305*7304104dSAndroid Build Coastguard Worker if (shdr->sh_type == SHT_NOBITS)
306*7304104dSAndroid Build Coastguard Worker goto next;
307*7304104dSAndroid Build Coastguard Worker
308*7304104dSAndroid Build Coastguard Worker char *scn_start = ((char *) elf->map_address
309*7304104dSAndroid Build Coastguard Worker + elf->start_offset + shdr->sh_offset);
310*7304104dSAndroid Build Coastguard Worker Elf_Data_List *dl = &scn->data_list;
311*7304104dSAndroid Build Coastguard Worker bool scn_changed = false;
312*7304104dSAndroid Build Coastguard Worker
313*7304104dSAndroid Build Coastguard Worker if (scn->data_list_rear != NULL)
314*7304104dSAndroid Build Coastguard Worker do
315*7304104dSAndroid Build Coastguard Worker {
316*7304104dSAndroid Build Coastguard Worker assert (dl->data.d.d_off >= 0);
317*7304104dSAndroid Build Coastguard Worker assert ((GElf_Off) dl->data.d.d_off <= shdr->sh_size);
318*7304104dSAndroid Build Coastguard Worker assert (dl->data.d.d_size <= (shdr->sh_size
319*7304104dSAndroid Build Coastguard Worker - (GElf_Off) dl->data.d.d_off));
320*7304104dSAndroid Build Coastguard Worker
321*7304104dSAndroid Build Coastguard Worker /* If there is a gap, fill it. */
322*7304104dSAndroid Build Coastguard Worker if (scn_start + dl->data.d.d_off > last_position
323*7304104dSAndroid Build Coastguard Worker && (dl->data.d.d_off == 0
324*7304104dSAndroid Build Coastguard Worker || ((scn->flags | dl->flags | elf->flags)
325*7304104dSAndroid Build Coastguard Worker & ELF_F_DIRTY) != 0))
326*7304104dSAndroid Build Coastguard Worker {
327*7304104dSAndroid Build Coastguard Worker fill_mmap (dl->data.d.d_off, last_position, scn_start,
328*7304104dSAndroid Build Coastguard Worker shdr_start, shdr_end);
329*7304104dSAndroid Build Coastguard Worker }
330*7304104dSAndroid Build Coastguard Worker
331*7304104dSAndroid Build Coastguard Worker last_position = scn_start + dl->data.d.d_off;
332*7304104dSAndroid Build Coastguard Worker
333*7304104dSAndroid Build Coastguard Worker if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY)
334*7304104dSAndroid Build Coastguard Worker {
335*7304104dSAndroid Build Coastguard Worker /* Let it go backward if the sections use a bogus
336*7304104dSAndroid Build Coastguard Worker layout with overlaps. We'll overwrite the stupid
337*7304104dSAndroid Build Coastguard Worker user's section data with the latest one, rather than
338*7304104dSAndroid Build Coastguard Worker crashing. */
339*7304104dSAndroid Build Coastguard Worker
340*7304104dSAndroid Build Coastguard Worker if (unlikely (change_bo
341*7304104dSAndroid Build Coastguard Worker && dl->data.d.d_size != 0
342*7304104dSAndroid Build Coastguard Worker && dl->data.d.d_type != ELF_T_BYTE))
343*7304104dSAndroid Build Coastguard Worker {
344*7304104dSAndroid Build Coastguard Worker #undef fctp
345*7304104dSAndroid Build Coastguard Worker #define fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type]
346*7304104dSAndroid Build Coastguard Worker
347*7304104dSAndroid Build Coastguard Worker size_t align;
348*7304104dSAndroid Build Coastguard Worker align = __libelf_type_align (ELFW(ELFCLASS,LIBELFBITS),
349*7304104dSAndroid Build Coastguard Worker dl->data.d.d_type);
350*7304104dSAndroid Build Coastguard Worker if ((((uintptr_t) last_position)
351*7304104dSAndroid Build Coastguard Worker & (uintptr_t) (align - 1)) == 0)
352*7304104dSAndroid Build Coastguard Worker {
353*7304104dSAndroid Build Coastguard Worker /* No need to copy, we can convert directly. */
354*7304104dSAndroid Build Coastguard Worker (*fctp) (last_position, dl->data.d.d_buf,
355*7304104dSAndroid Build Coastguard Worker dl->data.d.d_size, 1);
356*7304104dSAndroid Build Coastguard Worker }
357*7304104dSAndroid Build Coastguard Worker else
358*7304104dSAndroid Build Coastguard Worker {
359*7304104dSAndroid Build Coastguard Worker /* We have to do the conversion on properly
360*7304104dSAndroid Build Coastguard Worker aligned memory first. align is a power of 2,
361*7304104dSAndroid Build Coastguard Worker but posix_memalign only works for alignments
362*7304104dSAndroid Build Coastguard Worker which are a multiple of sizeof (void *).
363*7304104dSAndroid Build Coastguard Worker So use normal malloc for smaller alignments. */
364*7304104dSAndroid Build Coastguard Worker size_t size = dl->data.d.d_size;
365*7304104dSAndroid Build Coastguard Worker void *converted;
366*7304104dSAndroid Build Coastguard Worker if (align < sizeof (void *))
367*7304104dSAndroid Build Coastguard Worker converted = malloc (size);
368*7304104dSAndroid Build Coastguard Worker else
369*7304104dSAndroid Build Coastguard Worker {
370*7304104dSAndroid Build Coastguard Worker int res;
371*7304104dSAndroid Build Coastguard Worker res = posix_memalign (&converted, align, size);
372*7304104dSAndroid Build Coastguard Worker if (res != 0)
373*7304104dSAndroid Build Coastguard Worker converted = NULL;
374*7304104dSAndroid Build Coastguard Worker }
375*7304104dSAndroid Build Coastguard Worker
376*7304104dSAndroid Build Coastguard Worker if (converted == NULL)
377*7304104dSAndroid Build Coastguard Worker {
378*7304104dSAndroid Build Coastguard Worker free (scns);
379*7304104dSAndroid Build Coastguard Worker __libelf_seterrno (ELF_E_NOMEM);
380*7304104dSAndroid Build Coastguard Worker return 1;
381*7304104dSAndroid Build Coastguard Worker }
382*7304104dSAndroid Build Coastguard Worker
383*7304104dSAndroid Build Coastguard Worker (*fctp) (converted, dl->data.d.d_buf, size, 1);
384*7304104dSAndroid Build Coastguard Worker
385*7304104dSAndroid Build Coastguard Worker /* And then write it to the mmapped file. */
386*7304104dSAndroid Build Coastguard Worker memcpy (last_position, converted, size);
387*7304104dSAndroid Build Coastguard Worker free (converted);
388*7304104dSAndroid Build Coastguard Worker }
389*7304104dSAndroid Build Coastguard Worker
390*7304104dSAndroid Build Coastguard Worker last_position += dl->data.d.d_size;
391*7304104dSAndroid Build Coastguard Worker }
392*7304104dSAndroid Build Coastguard Worker else if (dl->data.d.d_size != 0)
393*7304104dSAndroid Build Coastguard Worker {
394*7304104dSAndroid Build Coastguard Worker memmove (last_position, dl->data.d.d_buf,
395*7304104dSAndroid Build Coastguard Worker dl->data.d.d_size);
396*7304104dSAndroid Build Coastguard Worker last_position += dl->data.d.d_size;
397*7304104dSAndroid Build Coastguard Worker }
398*7304104dSAndroid Build Coastguard Worker
399*7304104dSAndroid Build Coastguard Worker scn_changed = true;
400*7304104dSAndroid Build Coastguard Worker }
401*7304104dSAndroid Build Coastguard Worker else
402*7304104dSAndroid Build Coastguard Worker last_position += dl->data.d.d_size;
403*7304104dSAndroid Build Coastguard Worker
404*7304104dSAndroid Build Coastguard Worker assert (scn_start + dl->data.d.d_off + dl->data.d.d_size
405*7304104dSAndroid Build Coastguard Worker == last_position);
406*7304104dSAndroid Build Coastguard Worker
407*7304104dSAndroid Build Coastguard Worker dl->flags &= ~ELF_F_DIRTY;
408*7304104dSAndroid Build Coastguard Worker
409*7304104dSAndroid Build Coastguard Worker dl = dl->next;
410*7304104dSAndroid Build Coastguard Worker }
411*7304104dSAndroid Build Coastguard Worker while (dl != NULL);
412*7304104dSAndroid Build Coastguard Worker else
413*7304104dSAndroid Build Coastguard Worker {
414*7304104dSAndroid Build Coastguard Worker /* If the previous section (or the ELF/program
415*7304104dSAndroid Build Coastguard Worker header) changed we might have to fill the gap. */
416*7304104dSAndroid Build Coastguard Worker if (scn_start > last_position && previous_scn_changed)
417*7304104dSAndroid Build Coastguard Worker fill_mmap (0, last_position, scn_start,
418*7304104dSAndroid Build Coastguard Worker shdr_start, shdr_end);
419*7304104dSAndroid Build Coastguard Worker
420*7304104dSAndroid Build Coastguard Worker /* We have to trust the existing section header information. */
421*7304104dSAndroid Build Coastguard Worker last_position = scn_start + shdr->sh_size;
422*7304104dSAndroid Build Coastguard Worker }
423*7304104dSAndroid Build Coastguard Worker
424*7304104dSAndroid Build Coastguard Worker
425*7304104dSAndroid Build Coastguard Worker previous_scn_changed = scn_changed;
426*7304104dSAndroid Build Coastguard Worker next:
427*7304104dSAndroid Build Coastguard Worker scn->flags &= ~ELF_F_DIRTY;
428*7304104dSAndroid Build Coastguard Worker }
429*7304104dSAndroid Build Coastguard Worker
430*7304104dSAndroid Build Coastguard Worker /* Fill the gap between last section and section header table if
431*7304104dSAndroid Build Coastguard Worker necessary. */
432*7304104dSAndroid Build Coastguard Worker if ((elf->flags & ELF_F_DIRTY)
433*7304104dSAndroid Build Coastguard Worker && last_position < ((char *) elf->map_address + elf->start_offset
434*7304104dSAndroid Build Coastguard Worker + ehdr->e_shoff))
435*7304104dSAndroid Build Coastguard Worker memset (last_position, __libelf_fill_byte,
436*7304104dSAndroid Build Coastguard Worker (char *) elf->map_address + elf->start_offset + ehdr->e_shoff
437*7304104dSAndroid Build Coastguard Worker - last_position);
438*7304104dSAndroid Build Coastguard Worker
439*7304104dSAndroid Build Coastguard Worker /* Write the section header table entry if necessary. */
440*7304104dSAndroid Build Coastguard Worker for (size_t cnt = 0; cnt < shnum; ++cnt)
441*7304104dSAndroid Build Coastguard Worker {
442*7304104dSAndroid Build Coastguard Worker Elf_Scn *scn = scns[cnt];
443*7304104dSAndroid Build Coastguard Worker
444*7304104dSAndroid Build Coastguard Worker if ((scn->shdr_flags | elf->flags) & ELF_F_DIRTY)
445*7304104dSAndroid Build Coastguard Worker {
446*7304104dSAndroid Build Coastguard Worker if (unlikely (change_bo))
447*7304104dSAndroid Build Coastguard Worker (*shdr_fctp) (&shdr_dest[scn->index],
448*7304104dSAndroid Build Coastguard Worker scn->shdr.ELFW(e,LIBELFBITS),
449*7304104dSAndroid Build Coastguard Worker sizeof (ElfW2(LIBELFBITS,Shdr)), 1);
450*7304104dSAndroid Build Coastguard Worker else
451*7304104dSAndroid Build Coastguard Worker memcpy (&shdr_dest[scn->index],
452*7304104dSAndroid Build Coastguard Worker scn->shdr.ELFW(e,LIBELFBITS),
453*7304104dSAndroid Build Coastguard Worker sizeof (ElfW2(LIBELFBITS,Shdr)));
454*7304104dSAndroid Build Coastguard Worker
455*7304104dSAndroid Build Coastguard Worker /* If we previously made a copy of the section header
456*7304104dSAndroid Build Coastguard Worker entry we now have to adjust the pointer again so
457*7304104dSAndroid Build Coastguard Worker point to new place in the mapping. */
458*7304104dSAndroid Build Coastguard Worker if (!elf->state.ELFW(elf,LIBELFBITS).shdr_malloced
459*7304104dSAndroid Build Coastguard Worker && (scn->shdr_flags & ELF_F_MALLOCED) == 0
460*7304104dSAndroid Build Coastguard Worker && scn->shdr.ELFW(e,LIBELFBITS) != &shdr_dest[scn->index])
461*7304104dSAndroid Build Coastguard Worker {
462*7304104dSAndroid Build Coastguard Worker free (scn->shdr.ELFW(e,LIBELFBITS));
463*7304104dSAndroid Build Coastguard Worker scn->shdr.ELFW(e,LIBELFBITS) = &shdr_dest[scn->index];
464*7304104dSAndroid Build Coastguard Worker }
465*7304104dSAndroid Build Coastguard Worker
466*7304104dSAndroid Build Coastguard Worker scn->shdr_flags &= ~ELF_F_DIRTY;
467*7304104dSAndroid Build Coastguard Worker }
468*7304104dSAndroid Build Coastguard Worker }
469*7304104dSAndroid Build Coastguard Worker free (scns);
470*7304104dSAndroid Build Coastguard Worker }
471*7304104dSAndroid Build Coastguard Worker
472*7304104dSAndroid Build Coastguard Worker /* That was the last part. Clear the overall flag. */
473*7304104dSAndroid Build Coastguard Worker elf->flags &= ~ELF_F_DIRTY;
474*7304104dSAndroid Build Coastguard Worker
475*7304104dSAndroid Build Coastguard Worker /* Make sure the content hits the disk. */
476*7304104dSAndroid Build Coastguard Worker char *msync_start = ((char *) elf->map_address
477*7304104dSAndroid Build Coastguard Worker + (elf->start_offset & ~(sysconf (_SC_PAGESIZE) - 1)));
478*7304104dSAndroid Build Coastguard Worker char *msync_end = ((char *) elf->map_address
479*7304104dSAndroid Build Coastguard Worker + elf->start_offset + ehdr->e_shoff
480*7304104dSAndroid Build Coastguard Worker + ehdr->e_shentsize * shnum);
481*7304104dSAndroid Build Coastguard Worker (void) msync (msync_start, msync_end - msync_start, MS_SYNC);
482*7304104dSAndroid Build Coastguard Worker
483*7304104dSAndroid Build Coastguard Worker return 0;
484*7304104dSAndroid Build Coastguard Worker }
485*7304104dSAndroid Build Coastguard Worker
486*7304104dSAndroid Build Coastguard Worker
487*7304104dSAndroid Build Coastguard Worker /* Size of the buffer we use to generate the blocks of fill bytes. */
488*7304104dSAndroid Build Coastguard Worker #define FILLBUFSIZE 4096
489*7304104dSAndroid Build Coastguard Worker
490*7304104dSAndroid Build Coastguard Worker /* If we have to convert the section buffer contents we have to use
491*7304104dSAndroid Build Coastguard Worker temporary buffer. Only buffers up to MAX_TMPBUF bytes are allocated
492*7304104dSAndroid Build Coastguard Worker on the stack. */
493*7304104dSAndroid Build Coastguard Worker #define MAX_TMPBUF 32768
494*7304104dSAndroid Build Coastguard Worker
495*7304104dSAndroid Build Coastguard Worker
496*7304104dSAndroid Build Coastguard Worker /* Helper function to write out fill bytes. */
497*7304104dSAndroid Build Coastguard Worker static int
fill(int fd,int64_t pos,size_t len,char * fillbuf,size_t * filledp)498*7304104dSAndroid Build Coastguard Worker fill (int fd, int64_t pos, size_t len, char *fillbuf, size_t *filledp)
499*7304104dSAndroid Build Coastguard Worker {
500*7304104dSAndroid Build Coastguard Worker size_t filled = *filledp;
501*7304104dSAndroid Build Coastguard Worker size_t fill_len = MIN (len, FILLBUFSIZE);
502*7304104dSAndroid Build Coastguard Worker
503*7304104dSAndroid Build Coastguard Worker if (unlikely (fill_len > filled) && filled < FILLBUFSIZE)
504*7304104dSAndroid Build Coastguard Worker {
505*7304104dSAndroid Build Coastguard Worker /* Initialize a few more bytes. */
506*7304104dSAndroid Build Coastguard Worker memset (fillbuf + filled, __libelf_fill_byte, fill_len - filled);
507*7304104dSAndroid Build Coastguard Worker *filledp = filled = fill_len;
508*7304104dSAndroid Build Coastguard Worker }
509*7304104dSAndroid Build Coastguard Worker
510*7304104dSAndroid Build Coastguard Worker do
511*7304104dSAndroid Build Coastguard Worker {
512*7304104dSAndroid Build Coastguard Worker /* This many bytes we want to write in this round. */
513*7304104dSAndroid Build Coastguard Worker size_t n = MIN (filled, len);
514*7304104dSAndroid Build Coastguard Worker
515*7304104dSAndroid Build Coastguard Worker if (unlikely ((size_t) pwrite_retry (fd, fillbuf, n, pos) != n))
516*7304104dSAndroid Build Coastguard Worker {
517*7304104dSAndroid Build Coastguard Worker __libelf_seterrno (ELF_E_WRITE_ERROR);
518*7304104dSAndroid Build Coastguard Worker return 1;
519*7304104dSAndroid Build Coastguard Worker }
520*7304104dSAndroid Build Coastguard Worker
521*7304104dSAndroid Build Coastguard Worker pos += n;
522*7304104dSAndroid Build Coastguard Worker len -= n;
523*7304104dSAndroid Build Coastguard Worker }
524*7304104dSAndroid Build Coastguard Worker while (len > 0);
525*7304104dSAndroid Build Coastguard Worker
526*7304104dSAndroid Build Coastguard Worker return 0;
527*7304104dSAndroid Build Coastguard Worker }
528*7304104dSAndroid Build Coastguard Worker
529*7304104dSAndroid Build Coastguard Worker
530*7304104dSAndroid Build Coastguard Worker int
531*7304104dSAndroid Build Coastguard Worker internal_function
__elfw2(LIBELFBITS,updatefile)532*7304104dSAndroid Build Coastguard Worker __elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum)
533*7304104dSAndroid Build Coastguard Worker {
534*7304104dSAndroid Build Coastguard Worker char fillbuf[FILLBUFSIZE];
535*7304104dSAndroid Build Coastguard Worker size_t filled = 0;
536*7304104dSAndroid Build Coastguard Worker bool previous_scn_changed = false;
537*7304104dSAndroid Build Coastguard Worker
538*7304104dSAndroid Build Coastguard Worker /* We need the ELF header several times. */
539*7304104dSAndroid Build Coastguard Worker ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
540*7304104dSAndroid Build Coastguard Worker
541*7304104dSAndroid Build Coastguard Worker /* Write out the ELF header. */
542*7304104dSAndroid Build Coastguard Worker if ((elf->state.ELFW(elf,LIBELFBITS).ehdr_flags | elf->flags) & ELF_F_DIRTY)
543*7304104dSAndroid Build Coastguard Worker {
544*7304104dSAndroid Build Coastguard Worker ElfW2(LIBELFBITS,Ehdr) tmp_ehdr;
545*7304104dSAndroid Build Coastguard Worker ElfW2(LIBELFBITS,Ehdr) *out_ehdr = ehdr;
546*7304104dSAndroid Build Coastguard Worker
547*7304104dSAndroid Build Coastguard Worker /* If the type sizes should be different at some time we have to
548*7304104dSAndroid Build Coastguard Worker rewrite this code. */
549*7304104dSAndroid Build Coastguard Worker assert (sizeof (ElfW2(LIBELFBITS,Ehdr))
550*7304104dSAndroid Build Coastguard Worker == elf_typesize (LIBELFBITS, ELF_T_EHDR, 1));
551*7304104dSAndroid Build Coastguard Worker
552*7304104dSAndroid Build Coastguard Worker if (unlikely (change_bo))
553*7304104dSAndroid Build Coastguard Worker {
554*7304104dSAndroid Build Coastguard Worker /* Today there is only one version of the ELF header. */
555*7304104dSAndroid Build Coastguard Worker #undef fctp
556*7304104dSAndroid Build Coastguard Worker #define fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR]
557*7304104dSAndroid Build Coastguard Worker
558*7304104dSAndroid Build Coastguard Worker /* Write the converted ELF header in a temporary buffer. */
559*7304104dSAndroid Build Coastguard Worker (*fctp) (&tmp_ehdr, ehdr, sizeof (ElfW2(LIBELFBITS,Ehdr)), 1);
560*7304104dSAndroid Build Coastguard Worker
561*7304104dSAndroid Build Coastguard Worker /* This is the buffer we want to write. */
562*7304104dSAndroid Build Coastguard Worker out_ehdr = &tmp_ehdr;
563*7304104dSAndroid Build Coastguard Worker }
564*7304104dSAndroid Build Coastguard Worker
565*7304104dSAndroid Build Coastguard Worker /* Write out the ELF header. */
566*7304104dSAndroid Build Coastguard Worker if (unlikely (pwrite_retry (elf->fildes, out_ehdr,
567*7304104dSAndroid Build Coastguard Worker sizeof (ElfW2(LIBELFBITS,Ehdr)), 0)
568*7304104dSAndroid Build Coastguard Worker != sizeof (ElfW2(LIBELFBITS,Ehdr))))
569*7304104dSAndroid Build Coastguard Worker {
570*7304104dSAndroid Build Coastguard Worker __libelf_seterrno (ELF_E_WRITE_ERROR);
571*7304104dSAndroid Build Coastguard Worker return 1;
572*7304104dSAndroid Build Coastguard Worker }
573*7304104dSAndroid Build Coastguard Worker
574*7304104dSAndroid Build Coastguard Worker elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY;
575*7304104dSAndroid Build Coastguard Worker
576*7304104dSAndroid Build Coastguard Worker /* We start writing sections after the ELF header only if there is
577*7304104dSAndroid Build Coastguard Worker no program header. */
578*7304104dSAndroid Build Coastguard Worker previous_scn_changed = elf->state.ELFW(elf,LIBELFBITS).phdr == NULL;
579*7304104dSAndroid Build Coastguard Worker }
580*7304104dSAndroid Build Coastguard Worker
581*7304104dSAndroid Build Coastguard Worker /* If the type sizes should be different at some time we have to
582*7304104dSAndroid Build Coastguard Worker rewrite this code. */
583*7304104dSAndroid Build Coastguard Worker assert (sizeof (ElfW2(LIBELFBITS,Phdr))
584*7304104dSAndroid Build Coastguard Worker == elf_typesize (LIBELFBITS, ELF_T_PHDR, 1));
585*7304104dSAndroid Build Coastguard Worker
586*7304104dSAndroid Build Coastguard Worker size_t phnum;
587*7304104dSAndroid Build Coastguard Worker if (unlikely (__elf_getphdrnum_rdlock (elf, &phnum) != 0))
588*7304104dSAndroid Build Coastguard Worker return -1;
589*7304104dSAndroid Build Coastguard Worker
590*7304104dSAndroid Build Coastguard Worker /* Write out the program header table. */
591*7304104dSAndroid Build Coastguard Worker if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL
592*7304104dSAndroid Build Coastguard Worker && ((elf->state.ELFW(elf,LIBELFBITS).phdr_flags | elf->flags)
593*7304104dSAndroid Build Coastguard Worker & ELF_F_DIRTY))
594*7304104dSAndroid Build Coastguard Worker {
595*7304104dSAndroid Build Coastguard Worker ElfW2(LIBELFBITS,Phdr) *tmp_phdr = NULL;
596*7304104dSAndroid Build Coastguard Worker ElfW2(LIBELFBITS,Phdr) *out_phdr = elf->state.ELFW(elf,LIBELFBITS).phdr;
597*7304104dSAndroid Build Coastguard Worker
598*7304104dSAndroid Build Coastguard Worker /* Maybe the user wants a gap between the ELF header and the program
599*7304104dSAndroid Build Coastguard Worker header. */
600*7304104dSAndroid Build Coastguard Worker if (ehdr->e_phoff > ehdr->e_ehsize
601*7304104dSAndroid Build Coastguard Worker && unlikely (fill (elf->fildes, ehdr->e_ehsize,
602*7304104dSAndroid Build Coastguard Worker ehdr->e_phoff - ehdr->e_ehsize, fillbuf, &filled)
603*7304104dSAndroid Build Coastguard Worker != 0))
604*7304104dSAndroid Build Coastguard Worker return 1;
605*7304104dSAndroid Build Coastguard Worker
606*7304104dSAndroid Build Coastguard Worker if (unlikely (change_bo))
607*7304104dSAndroid Build Coastguard Worker {
608*7304104dSAndroid Build Coastguard Worker /* Today there is only one version of the ELF header. */
609*7304104dSAndroid Build Coastguard Worker #undef fctp
610*7304104dSAndroid Build Coastguard Worker #define fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR]
611*7304104dSAndroid Build Coastguard Worker
612*7304104dSAndroid Build Coastguard Worker /* Allocate sufficient memory. */
613*7304104dSAndroid Build Coastguard Worker tmp_phdr = (ElfW2(LIBELFBITS,Phdr) *)
614*7304104dSAndroid Build Coastguard Worker malloc (sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum);
615*7304104dSAndroid Build Coastguard Worker if (unlikely (tmp_phdr == NULL))
616*7304104dSAndroid Build Coastguard Worker {
617*7304104dSAndroid Build Coastguard Worker __libelf_seterrno (ELF_E_NOMEM);
618*7304104dSAndroid Build Coastguard Worker return 1;
619*7304104dSAndroid Build Coastguard Worker }
620*7304104dSAndroid Build Coastguard Worker
621*7304104dSAndroid Build Coastguard Worker /* Write the converted ELF header in a temporary buffer. */
622*7304104dSAndroid Build Coastguard Worker (*fctp) (tmp_phdr, elf->state.ELFW(elf,LIBELFBITS).phdr,
623*7304104dSAndroid Build Coastguard Worker sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum, 1);
624*7304104dSAndroid Build Coastguard Worker
625*7304104dSAndroid Build Coastguard Worker /* This is the buffer we want to write. */
626*7304104dSAndroid Build Coastguard Worker out_phdr = tmp_phdr;
627*7304104dSAndroid Build Coastguard Worker }
628*7304104dSAndroid Build Coastguard Worker
629*7304104dSAndroid Build Coastguard Worker /* Write out the ELF header. */
630*7304104dSAndroid Build Coastguard Worker size_t phdr_size = sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum;
631*7304104dSAndroid Build Coastguard Worker if (unlikely ((size_t) pwrite_retry (elf->fildes, out_phdr,
632*7304104dSAndroid Build Coastguard Worker phdr_size, ehdr->e_phoff)
633*7304104dSAndroid Build Coastguard Worker != phdr_size))
634*7304104dSAndroid Build Coastguard Worker {
635*7304104dSAndroid Build Coastguard Worker __libelf_seterrno (ELF_E_WRITE_ERROR);
636*7304104dSAndroid Build Coastguard Worker return 1;
637*7304104dSAndroid Build Coastguard Worker }
638*7304104dSAndroid Build Coastguard Worker
639*7304104dSAndroid Build Coastguard Worker /* This is a no-op we we have not allocated any memory. */
640*7304104dSAndroid Build Coastguard Worker free (tmp_phdr);
641*7304104dSAndroid Build Coastguard Worker
642*7304104dSAndroid Build Coastguard Worker elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY;
643*7304104dSAndroid Build Coastguard Worker
644*7304104dSAndroid Build Coastguard Worker /* We modified the program header. Maybe this created a gap so
645*7304104dSAndroid Build Coastguard Worker we have to write fill bytes, if necessary. */
646*7304104dSAndroid Build Coastguard Worker previous_scn_changed = true;
647*7304104dSAndroid Build Coastguard Worker }
648*7304104dSAndroid Build Coastguard Worker
649*7304104dSAndroid Build Coastguard Worker /* From now on we have to keep track of the last position to eventually
650*7304104dSAndroid Build Coastguard Worker fill the gaps with the prescribed fill byte. */
651*7304104dSAndroid Build Coastguard Worker int64_t last_offset;
652*7304104dSAndroid Build Coastguard Worker if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL)
653*7304104dSAndroid Build Coastguard Worker last_offset = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
654*7304104dSAndroid Build Coastguard Worker else
655*7304104dSAndroid Build Coastguard Worker last_offset = (ehdr->e_phoff + sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum);
656*7304104dSAndroid Build Coastguard Worker
657*7304104dSAndroid Build Coastguard Worker /* Write all the sections. Well, only those which are modified. */
658*7304104dSAndroid Build Coastguard Worker if (shnum > 0)
659*7304104dSAndroid Build Coastguard Worker {
660*7304104dSAndroid Build Coastguard Worker if (unlikely (shnum > SIZE_MAX / (sizeof (Elf_Scn *)
661*7304104dSAndroid Build Coastguard Worker + sizeof (ElfW2(LIBELFBITS,Shdr)))))
662*7304104dSAndroid Build Coastguard Worker return 1;
663*7304104dSAndroid Build Coastguard Worker
664*7304104dSAndroid Build Coastguard Worker int64_t shdr_offset = elf->start_offset + ehdr->e_shoff;
665*7304104dSAndroid Build Coastguard Worker #undef shdr_fctp
666*7304104dSAndroid Build Coastguard Worker #define shdr_fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR]
667*7304104dSAndroid Build Coastguard Worker
668*7304104dSAndroid Build Coastguard Worker ElfW2(LIBELFBITS,Shdr) *shdr_data;
669*7304104dSAndroid Build Coastguard Worker ElfW2(LIBELFBITS,Shdr) *shdr_data_mem = NULL;
670*7304104dSAndroid Build Coastguard Worker if (change_bo || elf->state.ELFW(elf,LIBELFBITS).shdr == NULL
671*7304104dSAndroid Build Coastguard Worker || (elf->flags & ELF_F_DIRTY))
672*7304104dSAndroid Build Coastguard Worker {
673*7304104dSAndroid Build Coastguard Worker shdr_data_mem = (ElfW2(LIBELFBITS,Shdr) *)
674*7304104dSAndroid Build Coastguard Worker malloc (shnum * sizeof (ElfW2(LIBELFBITS,Shdr)));
675*7304104dSAndroid Build Coastguard Worker if (unlikely (shdr_data_mem == NULL))
676*7304104dSAndroid Build Coastguard Worker {
677*7304104dSAndroid Build Coastguard Worker __libelf_seterrno (ELF_E_NOMEM);
678*7304104dSAndroid Build Coastguard Worker return -1;
679*7304104dSAndroid Build Coastguard Worker }
680*7304104dSAndroid Build Coastguard Worker shdr_data = shdr_data_mem;
681*7304104dSAndroid Build Coastguard Worker }
682*7304104dSAndroid Build Coastguard Worker else
683*7304104dSAndroid Build Coastguard Worker shdr_data = elf->state.ELFW(elf,LIBELFBITS).shdr;
684*7304104dSAndroid Build Coastguard Worker int shdr_flags = elf->flags;
685*7304104dSAndroid Build Coastguard Worker
686*7304104dSAndroid Build Coastguard Worker /* Get all sections into the array and sort them. */
687*7304104dSAndroid Build Coastguard Worker Elf_ScnList *list = &elf->state.ELFW(elf,LIBELFBITS).scns;
688*7304104dSAndroid Build Coastguard Worker Elf_Scn **scns = malloc (shnum * sizeof (Elf_Scn *));
689*7304104dSAndroid Build Coastguard Worker if (unlikely (scns == NULL))
690*7304104dSAndroid Build Coastguard Worker {
691*7304104dSAndroid Build Coastguard Worker free (shdr_data_mem);
692*7304104dSAndroid Build Coastguard Worker __libelf_seterrno (ELF_E_NOMEM);
693*7304104dSAndroid Build Coastguard Worker return -1;
694*7304104dSAndroid Build Coastguard Worker }
695*7304104dSAndroid Build Coastguard Worker sort_sections (scns, list);
696*7304104dSAndroid Build Coastguard Worker
697*7304104dSAndroid Build Coastguard Worker for (size_t cnt = 0; cnt < shnum; ++cnt)
698*7304104dSAndroid Build Coastguard Worker {
699*7304104dSAndroid Build Coastguard Worker Elf_Scn *scn = scns[cnt];
700*7304104dSAndroid Build Coastguard Worker if (scn->index == 0)
701*7304104dSAndroid Build Coastguard Worker {
702*7304104dSAndroid Build Coastguard Worker /* The dummy section header entry. It should not be
703*7304104dSAndroid Build Coastguard Worker possible to mark this "section" as dirty. */
704*7304104dSAndroid Build Coastguard Worker assert ((scn->flags & ELF_F_DIRTY) == 0);
705*7304104dSAndroid Build Coastguard Worker goto next;
706*7304104dSAndroid Build Coastguard Worker }
707*7304104dSAndroid Build Coastguard Worker
708*7304104dSAndroid Build Coastguard Worker ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
709*7304104dSAndroid Build Coastguard Worker if (shdr->sh_type == SHT_NOBITS)
710*7304104dSAndroid Build Coastguard Worker goto next;
711*7304104dSAndroid Build Coastguard Worker
712*7304104dSAndroid Build Coastguard Worker int64_t scn_start = elf->start_offset + shdr->sh_offset;
713*7304104dSAndroid Build Coastguard Worker Elf_Data_List *dl = &scn->data_list;
714*7304104dSAndroid Build Coastguard Worker bool scn_changed = false;
715*7304104dSAndroid Build Coastguard Worker
716*7304104dSAndroid Build Coastguard Worker if (scn->data_list_rear != NULL)
717*7304104dSAndroid Build Coastguard Worker do
718*7304104dSAndroid Build Coastguard Worker {
719*7304104dSAndroid Build Coastguard Worker /* If there is a gap, fill it. */
720*7304104dSAndroid Build Coastguard Worker if (scn_start + dl->data.d.d_off > last_offset
721*7304104dSAndroid Build Coastguard Worker && ((previous_scn_changed && dl->data.d.d_off == 0)
722*7304104dSAndroid Build Coastguard Worker || ((scn->flags | dl->flags | elf->flags)
723*7304104dSAndroid Build Coastguard Worker & ELF_F_DIRTY) != 0))
724*7304104dSAndroid Build Coastguard Worker {
725*7304104dSAndroid Build Coastguard Worker if (unlikely (fill (elf->fildes, last_offset,
726*7304104dSAndroid Build Coastguard Worker (scn_start + dl->data.d.d_off)
727*7304104dSAndroid Build Coastguard Worker - last_offset, fillbuf,
728*7304104dSAndroid Build Coastguard Worker &filled) != 0))
729*7304104dSAndroid Build Coastguard Worker {
730*7304104dSAndroid Build Coastguard Worker fail_free:
731*7304104dSAndroid Build Coastguard Worker free (shdr_data_mem);
732*7304104dSAndroid Build Coastguard Worker free (scns);
733*7304104dSAndroid Build Coastguard Worker return 1;
734*7304104dSAndroid Build Coastguard Worker }
735*7304104dSAndroid Build Coastguard Worker }
736*7304104dSAndroid Build Coastguard Worker
737*7304104dSAndroid Build Coastguard Worker last_offset = scn_start + dl->data.d.d_off;
738*7304104dSAndroid Build Coastguard Worker
739*7304104dSAndroid Build Coastguard Worker if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY)
740*7304104dSAndroid Build Coastguard Worker {
741*7304104dSAndroid Build Coastguard Worker char tmpbuf[MAX_TMPBUF];
742*7304104dSAndroid Build Coastguard Worker void *buf = dl->data.d.d_buf;
743*7304104dSAndroid Build Coastguard Worker
744*7304104dSAndroid Build Coastguard Worker /* Let it go backward if the sections use a bogus
745*7304104dSAndroid Build Coastguard Worker layout with overlaps. We'll overwrite the stupid
746*7304104dSAndroid Build Coastguard Worker user's section data with the latest one, rather than
747*7304104dSAndroid Build Coastguard Worker crashing. */
748*7304104dSAndroid Build Coastguard Worker
749*7304104dSAndroid Build Coastguard Worker if (unlikely (change_bo))
750*7304104dSAndroid Build Coastguard Worker {
751*7304104dSAndroid Build Coastguard Worker #undef fctp
752*7304104dSAndroid Build Coastguard Worker #define fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type]
753*7304104dSAndroid Build Coastguard Worker
754*7304104dSAndroid Build Coastguard Worker buf = tmpbuf;
755*7304104dSAndroid Build Coastguard Worker if (dl->data.d.d_size > MAX_TMPBUF)
756*7304104dSAndroid Build Coastguard Worker {
757*7304104dSAndroid Build Coastguard Worker buf = malloc (dl->data.d.d_size);
758*7304104dSAndroid Build Coastguard Worker if (unlikely (buf == NULL))
759*7304104dSAndroid Build Coastguard Worker {
760*7304104dSAndroid Build Coastguard Worker __libelf_seterrno (ELF_E_NOMEM);
761*7304104dSAndroid Build Coastguard Worker goto fail_free;
762*7304104dSAndroid Build Coastguard Worker }
763*7304104dSAndroid Build Coastguard Worker }
764*7304104dSAndroid Build Coastguard Worker
765*7304104dSAndroid Build Coastguard Worker /* Do the real work. */
766*7304104dSAndroid Build Coastguard Worker (*fctp) (buf, dl->data.d.d_buf, dl->data.d.d_size, 1);
767*7304104dSAndroid Build Coastguard Worker }
768*7304104dSAndroid Build Coastguard Worker
769*7304104dSAndroid Build Coastguard Worker ssize_t n = pwrite_retry (elf->fildes, buf,
770*7304104dSAndroid Build Coastguard Worker dl->data.d.d_size,
771*7304104dSAndroid Build Coastguard Worker last_offset);
772*7304104dSAndroid Build Coastguard Worker if (unlikely ((size_t) n != dl->data.d.d_size))
773*7304104dSAndroid Build Coastguard Worker {
774*7304104dSAndroid Build Coastguard Worker if (buf != dl->data.d.d_buf && buf != tmpbuf)
775*7304104dSAndroid Build Coastguard Worker free (buf);
776*7304104dSAndroid Build Coastguard Worker
777*7304104dSAndroid Build Coastguard Worker __libelf_seterrno (ELF_E_WRITE_ERROR);
778*7304104dSAndroid Build Coastguard Worker goto fail_free;
779*7304104dSAndroid Build Coastguard Worker }
780*7304104dSAndroid Build Coastguard Worker
781*7304104dSAndroid Build Coastguard Worker if (buf != dl->data.d.d_buf && buf != tmpbuf)
782*7304104dSAndroid Build Coastguard Worker free (buf);
783*7304104dSAndroid Build Coastguard Worker
784*7304104dSAndroid Build Coastguard Worker scn_changed = true;
785*7304104dSAndroid Build Coastguard Worker }
786*7304104dSAndroid Build Coastguard Worker
787*7304104dSAndroid Build Coastguard Worker last_offset += dl->data.d.d_size;
788*7304104dSAndroid Build Coastguard Worker
789*7304104dSAndroid Build Coastguard Worker dl->flags &= ~ELF_F_DIRTY;
790*7304104dSAndroid Build Coastguard Worker
791*7304104dSAndroid Build Coastguard Worker dl = dl->next;
792*7304104dSAndroid Build Coastguard Worker }
793*7304104dSAndroid Build Coastguard Worker while (dl != NULL);
794*7304104dSAndroid Build Coastguard Worker else
795*7304104dSAndroid Build Coastguard Worker {
796*7304104dSAndroid Build Coastguard Worker /* If the previous section (or the ELF/program
797*7304104dSAndroid Build Coastguard Worker header) changed we might have to fill the gap. */
798*7304104dSAndroid Build Coastguard Worker if (scn_start > last_offset && previous_scn_changed)
799*7304104dSAndroid Build Coastguard Worker {
800*7304104dSAndroid Build Coastguard Worker if (unlikely (fill (elf->fildes, last_offset,
801*7304104dSAndroid Build Coastguard Worker scn_start - last_offset, fillbuf,
802*7304104dSAndroid Build Coastguard Worker &filled) != 0))
803*7304104dSAndroid Build Coastguard Worker goto fail_free;
804*7304104dSAndroid Build Coastguard Worker }
805*7304104dSAndroid Build Coastguard Worker
806*7304104dSAndroid Build Coastguard Worker last_offset = scn_start + shdr->sh_size;
807*7304104dSAndroid Build Coastguard Worker }
808*7304104dSAndroid Build Coastguard Worker
809*7304104dSAndroid Build Coastguard Worker previous_scn_changed = scn_changed;
810*7304104dSAndroid Build Coastguard Worker next:
811*7304104dSAndroid Build Coastguard Worker /* Collect the section header table information. */
812*7304104dSAndroid Build Coastguard Worker if (unlikely (change_bo))
813*7304104dSAndroid Build Coastguard Worker (*shdr_fctp) (&shdr_data[scn->index],
814*7304104dSAndroid Build Coastguard Worker scn->shdr.ELFW(e,LIBELFBITS),
815*7304104dSAndroid Build Coastguard Worker sizeof (ElfW2(LIBELFBITS,Shdr)), 1);
816*7304104dSAndroid Build Coastguard Worker else if (elf->state.ELFW(elf,LIBELFBITS).shdr == NULL
817*7304104dSAndroid Build Coastguard Worker || (elf->flags & ELF_F_DIRTY))
818*7304104dSAndroid Build Coastguard Worker memcpy (&shdr_data[scn->index], scn->shdr.ELFW(e,LIBELFBITS),
819*7304104dSAndroid Build Coastguard Worker sizeof (ElfW2(LIBELFBITS,Shdr)));
820*7304104dSAndroid Build Coastguard Worker
821*7304104dSAndroid Build Coastguard Worker shdr_flags |= scn->shdr_flags;
822*7304104dSAndroid Build Coastguard Worker scn->shdr_flags &= ~ELF_F_DIRTY;
823*7304104dSAndroid Build Coastguard Worker }
824*7304104dSAndroid Build Coastguard Worker
825*7304104dSAndroid Build Coastguard Worker /* Fill the gap between last section and section header table if
826*7304104dSAndroid Build Coastguard Worker necessary. */
827*7304104dSAndroid Build Coastguard Worker if ((elf->flags & ELF_F_DIRTY) && last_offset < shdr_offset
828*7304104dSAndroid Build Coastguard Worker && unlikely (fill (elf->fildes, last_offset,
829*7304104dSAndroid Build Coastguard Worker shdr_offset - last_offset,
830*7304104dSAndroid Build Coastguard Worker fillbuf, &filled) != 0))
831*7304104dSAndroid Build Coastguard Worker goto fail_free;
832*7304104dSAndroid Build Coastguard Worker
833*7304104dSAndroid Build Coastguard Worker /* Write out the section header table. */
834*7304104dSAndroid Build Coastguard Worker if (shdr_flags & ELF_F_DIRTY
835*7304104dSAndroid Build Coastguard Worker && unlikely ((size_t) pwrite_retry (elf->fildes, shdr_data,
836*7304104dSAndroid Build Coastguard Worker sizeof (ElfW2(LIBELFBITS,Shdr))
837*7304104dSAndroid Build Coastguard Worker * shnum, shdr_offset)
838*7304104dSAndroid Build Coastguard Worker != sizeof (ElfW2(LIBELFBITS,Shdr)) * shnum))
839*7304104dSAndroid Build Coastguard Worker {
840*7304104dSAndroid Build Coastguard Worker __libelf_seterrno (ELF_E_WRITE_ERROR);
841*7304104dSAndroid Build Coastguard Worker goto fail_free;
842*7304104dSAndroid Build Coastguard Worker }
843*7304104dSAndroid Build Coastguard Worker
844*7304104dSAndroid Build Coastguard Worker free (shdr_data_mem);
845*7304104dSAndroid Build Coastguard Worker free (scns);
846*7304104dSAndroid Build Coastguard Worker }
847*7304104dSAndroid Build Coastguard Worker
848*7304104dSAndroid Build Coastguard Worker /* That was the last part. Clear the overall flag. */
849*7304104dSAndroid Build Coastguard Worker elf->flags &= ~ELF_F_DIRTY;
850*7304104dSAndroid Build Coastguard Worker
851*7304104dSAndroid Build Coastguard Worker return 0;
852*7304104dSAndroid Build Coastguard Worker }
853