Git init
[external/libelf.git] / lib / update.c
1 /*
2  * update.c - implementation of the elf_update(3) function.
3  * Copyright (C) 1995 - 2006 Michael Riepe
4  * 
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  * 
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  * 
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19
20 #include <private.h>
21
22 #ifndef lint
23 static const char rcsid[] = "@(#) $Id: update.c,v 1.34 2009/05/22 17:08:09 michael Exp $";
24 #endif /* lint */
25
26 #include <errno.h>
27
28 #if HAVE_MMAP
29 #include <sys/mman.h>
30 #endif /* HAVE_MMAP */
31
32 static const unsigned short __encoding = ELFDATA2LSB + (ELFDATA2MSB << 8);
33 #define native_encoding (*(unsigned char*)&__encoding)
34
35 #define rewrite(var,val,f)      \
36     do{if((var)!=(val)){(var)=(val);(f)|=ELF_F_DIRTY;}}while(0)
37
38 #define align(var,val)          \
39     do{if((val)>1){(var)+=(val)-1;(var)-=(var)%(val);}}while(0)
40
41 #undef max
42 #define max(a,b)                ((a)>(b)?(a):(b))
43
44 static off_t
45 scn_data_layout(Elf_Scn *scn, unsigned v, unsigned type, size_t *algn, unsigned *flag) {
46     Elf *elf = scn->s_elf;
47     Elf_Data *data;
48     int layout = (elf->e_elf_flags & ELF_F_LAYOUT) == 0;
49     size_t scn_align = 1;
50     size_t len = 0;
51     Scn_Data *sd;
52     size_t fsize;
53
54     if (!(sd = scn->s_data_1)) {
55         /* no data in section */
56         *algn = scn_align;
57         return (off_t)len;
58     }
59     /* load data from file, if any */
60     if (!(data = elf_getdata(scn, NULL))) {
61         return (off_t)-1;
62     }
63     elf_assert(data == &sd->sd_data);
64     for (; sd; sd = sd->sd_link) {
65         elf_assert(sd->sd_magic == DATA_MAGIC);
66         elf_assert(sd->sd_scn == scn);
67
68         if (!valid_version(sd->sd_data.d_version)) {
69             return (off_t)-1;
70         }
71
72         fsize = sd->sd_data.d_size;
73         if (fsize && type != SHT_NOBITS && valid_type(sd->sd_data.d_type)) {
74             if (elf->e_class == ELFCLASS32) {
75                 fsize = _elf32_xltsize(&sd->sd_data, v, ELFDATA2LSB, 1);
76             }
77 #if __LIBELF64
78             else if (elf->e_class == ELFCLASS64) {
79                 fsize = _elf64_xltsize(&sd->sd_data, v, ELFDATA2LSB, 1);
80             }
81 #endif /* __LIBELF64 */
82             else {
83                 elf_assert(valid_class(elf->e_class));
84                 seterr(ERROR_UNIMPLEMENTED);
85                 return (off_t)-1;
86             }
87             if (fsize == (size_t)-1) {
88                 return (off_t)-1;
89             }
90         }
91
92         if (layout) {
93             align(len, sd->sd_data.d_align);
94             scn_align = max(scn_align, sd->sd_data.d_align);
95             rewrite(sd->sd_data.d_off, (off_t)len, sd->sd_data_flags);
96             len += fsize;
97         }
98         else {
99             len = max(len, sd->sd_data.d_off + fsize);
100         }
101
102         *flag |= sd->sd_data_flags;
103     }
104     *algn = scn_align;
105     return (off_t)len;
106 }
107
108 static size_t
109 scn_entsize(const Elf *elf, unsigned version, unsigned stype) {
110     Elf_Type type;
111
112     switch ((type = _elf_scn_type(stype))) {
113         case ELF_T_BYTE:
114             return 0;
115         case ELF_T_VDEF:
116         case ELF_T_VNEED:
117             return 0;   /* What else can I do?  Thank you, Sun! */
118         default:
119             return _fsize(elf->e_class, version, type);
120     }
121 }
122
123 static off_t
124 _elf32_layout(Elf *elf, unsigned *flag) {
125     int layout = (elf->e_elf_flags & ELF_F_LAYOUT) == 0;
126     int allow_overlap = (elf->e_elf_flags & ELF_F_LAYOUT_OVERLAP) != 0;
127     Elf32_Ehdr *ehdr = (Elf32_Ehdr*)elf->e_ehdr;
128     size_t off = 0;
129     unsigned version;
130     unsigned encoding;
131     size_t align_addr;
132     size_t entsize;
133     unsigned phnum;
134     unsigned shnum;
135     Elf_Scn *scn;
136
137     *flag = elf->e_elf_flags | elf->e_phdr_flags;
138
139     if ((version = ehdr->e_version) == EV_NONE) {
140         version = EV_CURRENT;
141     }
142     if (!valid_version(version)) {
143         seterr(ERROR_UNKNOWN_VERSION);
144         return -1;
145     }
146     if ((encoding = ehdr->e_ident[EI_DATA]) == ELFDATANONE) {
147         encoding = native_encoding;
148     }
149     if (!valid_encoding(encoding)) {
150         seterr(ERROR_UNKNOWN_ENCODING);
151         return -1;
152     }
153     entsize = _fsize(ELFCLASS32, version, ELF_T_EHDR);
154     elf_assert(entsize);
155     rewrite(ehdr->e_ehsize, entsize, elf->e_ehdr_flags);
156     off = entsize;
157
158     align_addr = _fsize(ELFCLASS32, version, ELF_T_ADDR);
159     elf_assert(align_addr);
160
161     if ((phnum = elf->e_phnum)) {
162         entsize = _fsize(ELFCLASS32, version, ELF_T_PHDR);
163         elf_assert(entsize);
164         if (layout) {
165             align(off, align_addr);
166             rewrite(ehdr->e_phoff, off, elf->e_ehdr_flags);
167             off += phnum * entsize;
168         }
169         else {
170             off = max(off, ehdr->e_phoff + phnum * entsize);
171         }
172     }
173     else {
174         entsize = 0;
175         if (layout) {
176             rewrite(ehdr->e_phoff, 0, elf->e_ehdr_flags);
177         }
178     }
179     if (phnum >= PN_XNUM) {
180         Elf_Scn *scn = elf->e_scn_1;
181         Elf32_Shdr *shdr = &scn->s_shdr32;
182
183         elf_assert(scn);
184         elf_assert(scn->s_index == 0);
185         rewrite(shdr->sh_info, phnum, scn->s_shdr_flags);
186         *flag |= scn->s_shdr_flags;
187         phnum = PN_XNUM;
188     }
189     rewrite(ehdr->e_phnum, phnum, elf->e_ehdr_flags);
190     rewrite(ehdr->e_phentsize, entsize, elf->e_ehdr_flags);
191
192     for (scn = elf->e_scn_1, shnum = 0; scn; scn = scn->s_link, ++shnum) {
193         Elf32_Shdr *shdr = &scn->s_shdr32;
194         size_t scn_align = 1;
195         off_t len;
196
197         elf_assert(scn->s_index == shnum);
198
199         *flag |= scn->s_scn_flags;
200
201         if (scn->s_index == SHN_UNDEF) {
202             rewrite(shdr->sh_entsize, 0, scn->s_shdr_flags);
203             if (layout) {
204                 rewrite(shdr->sh_offset, 0, scn->s_shdr_flags);
205                 rewrite(shdr->sh_size, 0, scn->s_shdr_flags);
206                 rewrite(shdr->sh_addralign, 0, scn->s_shdr_flags);
207             }
208             *flag |= scn->s_shdr_flags;
209             continue;
210         }
211         if (shdr->sh_type == SHT_NULL) {
212             *flag |= scn->s_shdr_flags;
213             continue;
214         }
215
216         len = scn_data_layout(scn, version, shdr->sh_type, &scn_align, flag);
217         if (len == -1) {
218             return -1;
219         }
220
221         /*
222          * Never override the program's choice.
223          */
224         if (shdr->sh_entsize == 0) {
225             entsize = scn_entsize(elf, version, shdr->sh_type);
226             if (entsize > 1) {
227                 rewrite(shdr->sh_entsize, entsize, scn->s_shdr_flags);
228             }
229         }
230
231         if (layout) {
232             align(off, scn_align);
233             rewrite(shdr->sh_offset, off, scn->s_shdr_flags);
234             rewrite(shdr->sh_size, (size_t)len, scn->s_shdr_flags);
235             rewrite(shdr->sh_addralign, scn_align, scn->s_shdr_flags);
236
237             if (shdr->sh_type != SHT_NOBITS) {
238                 off += (size_t)len;
239             }
240         }
241         else if ((size_t)len > shdr->sh_size) {
242             seterr(ERROR_SCN2SMALL);
243             return -1;
244         }
245         else {
246             Elf_Scn *scn2;
247             size_t end1, end2;
248
249             end1 = shdr->sh_offset;
250             if (shdr->sh_type != SHT_NOBITS) {
251                 end1 += shdr->sh_size;
252             }
253             if (!allow_overlap && shdr->sh_offset < off) {
254                 /*
255                  * check for overlapping sections
256                  */
257                 for (scn2 = elf->e_scn_1; scn2; scn2 = scn2->s_link) {
258                     if (scn2 == scn) {
259                         break;
260                     }
261                     end2 = scn2->s_shdr32.sh_offset;
262                     if (scn2->s_shdr32.sh_type != SHT_NOBITS) {
263                         end2 += scn2->s_shdr32.sh_size;
264                     }
265                     if (end1 > scn2->s_shdr32.sh_offset
266                      && end2 > shdr->sh_offset) {
267                         seterr(ERROR_SCN_OVERLAP);
268                         return -1;
269                     }
270                 }
271             }
272             if (off < end1) {
273                 off = end1;
274             }
275         }
276         *flag |= scn->s_shdr_flags;
277     }
278
279     if (shnum) {
280         entsize = _fsize(ELFCLASS32, version, ELF_T_SHDR);
281         elf_assert(entsize);
282         if (layout) {
283             align(off, align_addr);
284             rewrite(ehdr->e_shoff, off, elf->e_ehdr_flags);
285             off += shnum * entsize;
286         }
287         else {
288             off = max(off, ehdr->e_shoff + shnum * entsize);
289         }
290     }
291     else {
292         entsize = 0;
293         if (layout) {
294             rewrite(ehdr->e_shoff, 0, elf->e_ehdr_flags);
295         }
296     }
297     if (shnum >= SHN_LORESERVE) {
298         Elf_Scn *scn = elf->e_scn_1;
299         Elf32_Shdr *shdr = &scn->s_shdr32;
300
301         elf_assert(scn->s_index == 0);
302         rewrite(shdr->sh_size, shnum, scn->s_shdr_flags);
303         *flag |= scn->s_shdr_flags;
304         shnum = 0;
305     }
306     rewrite(ehdr->e_shnum, shnum, elf->e_ehdr_flags);
307     rewrite(ehdr->e_shentsize, entsize, elf->e_ehdr_flags);
308
309     rewrite(ehdr->e_ident[EI_MAG0], ELFMAG0, elf->e_ehdr_flags);
310     rewrite(ehdr->e_ident[EI_MAG1], ELFMAG1, elf->e_ehdr_flags);
311     rewrite(ehdr->e_ident[EI_MAG2], ELFMAG2, elf->e_ehdr_flags);
312     rewrite(ehdr->e_ident[EI_MAG3], ELFMAG3, elf->e_ehdr_flags);
313     rewrite(ehdr->e_ident[EI_CLASS], ELFCLASS32, elf->e_ehdr_flags);
314     rewrite(ehdr->e_ident[EI_DATA], encoding, elf->e_ehdr_flags);
315     rewrite(ehdr->e_ident[EI_VERSION], version, elf->e_ehdr_flags);
316     rewrite(ehdr->e_version, version, elf->e_ehdr_flags);
317
318     *flag |= elf->e_ehdr_flags;
319
320     return off;
321 }
322
323 #if __LIBELF64
324
325 static off_t
326 _elf64_layout(Elf *elf, unsigned *flag) {
327     int layout = (elf->e_elf_flags & ELF_F_LAYOUT) == 0;
328     int allow_overlap = (elf->e_elf_flags & ELF_F_LAYOUT_OVERLAP) != 0;
329     Elf64_Ehdr *ehdr = (Elf64_Ehdr*)elf->e_ehdr;
330     size_t off = 0;
331     unsigned version;
332     unsigned encoding;
333     size_t align_addr;
334     size_t entsize;
335     unsigned phnum;
336     unsigned shnum;
337     Elf_Scn *scn;
338
339     *flag = elf->e_elf_flags | elf->e_phdr_flags;
340
341     if ((version = ehdr->e_version) == EV_NONE) {
342         version = EV_CURRENT;
343     }
344     if (!valid_version(version)) {
345         seterr(ERROR_UNKNOWN_VERSION);
346         return -1;
347     }
348     if ((encoding = ehdr->e_ident[EI_DATA]) == ELFDATANONE) {
349         encoding = native_encoding;
350     }
351     if (!valid_encoding(encoding)) {
352         seterr(ERROR_UNKNOWN_ENCODING);
353         return -1;
354     }
355     entsize = _fsize(ELFCLASS64, version, ELF_T_EHDR);
356     elf_assert(entsize);
357     rewrite(ehdr->e_ehsize, entsize, elf->e_ehdr_flags);
358     off = entsize;
359
360     align_addr = _fsize(ELFCLASS64, version, ELF_T_ADDR);
361     elf_assert(align_addr);
362
363     if ((phnum = elf->e_phnum)) {
364         entsize = _fsize(ELFCLASS64, version, ELF_T_PHDR);
365         elf_assert(entsize);
366         if (layout) {
367             align(off, align_addr);
368             rewrite(ehdr->e_phoff, off, elf->e_ehdr_flags);
369             off += phnum * entsize;
370         }
371         else {
372             off = max(off, ehdr->e_phoff + phnum * entsize);
373         }
374     }
375     else {
376         entsize = 0;
377         if (layout) {
378             rewrite(ehdr->e_phoff, 0, elf->e_ehdr_flags);
379         }
380     }
381     if (phnum >= PN_XNUM) {
382         Elf_Scn *scn = elf->e_scn_1;
383         Elf32_Shdr *shdr = &scn->s_shdr32;
384
385         /* modify first section header, too! */
386         elf_assert(scn);
387         elf_assert(scn->s_index == 0);
388         rewrite(shdr->sh_info, phnum, scn->s_shdr_flags);
389         *flag |= scn->s_shdr_flags;
390         phnum = PN_XNUM;
391     }
392     rewrite(ehdr->e_phnum, phnum, elf->e_ehdr_flags);
393     rewrite(ehdr->e_phentsize, entsize, elf->e_ehdr_flags);
394
395     for (scn = elf->e_scn_1, shnum = 0; scn; scn = scn->s_link, ++shnum) {
396         Elf64_Shdr *shdr = &scn->s_shdr64;
397         size_t scn_align = 1;
398         off_t len;
399
400         elf_assert(scn->s_index == shnum);
401
402         *flag |= scn->s_scn_flags;
403
404         if (scn->s_index == SHN_UNDEF) {
405             rewrite(shdr->sh_entsize, 0, scn->s_shdr_flags);
406             if (layout) {
407                 rewrite(shdr->sh_offset, 0, scn->s_shdr_flags);
408                 rewrite(shdr->sh_size, 0, scn->s_shdr_flags);
409                 rewrite(shdr->sh_addralign, 0, scn->s_shdr_flags);
410             }
411             *flag |= scn->s_shdr_flags;
412             continue;
413         }
414         if (shdr->sh_type == SHT_NULL) {
415             *flag |= scn->s_shdr_flags;
416             continue;
417         }
418
419         len = scn_data_layout(scn, version, shdr->sh_type, &scn_align, flag);
420         if (len == -1) {
421             return -1;
422         }
423
424         /*
425          * Never override the program's choice.
426          */
427         if (shdr->sh_entsize == 0) {
428             entsize = scn_entsize(elf, version, shdr->sh_type);
429             if (entsize > 1) {
430                 rewrite(shdr->sh_entsize, entsize, scn->s_shdr_flags);
431             }
432         }
433
434         if (layout) {
435             align(off, scn_align);
436             rewrite(shdr->sh_offset, off, scn->s_shdr_flags);
437             rewrite(shdr->sh_size, (size_t)len, scn->s_shdr_flags);
438             rewrite(shdr->sh_addralign, scn_align, scn->s_shdr_flags);
439
440             if (shdr->sh_type != SHT_NOBITS) {
441                 off += (size_t)len;
442             }
443         }
444         else if ((size_t)len > shdr->sh_size) {
445             seterr(ERROR_SCN2SMALL);
446             return -1;
447         }
448         else {
449             Elf_Scn *scn2;
450             size_t end1, end2;
451
452             end1 = shdr->sh_offset;
453             if (shdr->sh_type != SHT_NOBITS) {
454                 end1 += shdr->sh_size;
455             }
456             if (!allow_overlap && shdr->sh_offset < off) {
457                 /*
458                  * check for overlapping sections
459                  */
460                 for (scn2 = elf->e_scn_1; scn2; scn2 = scn2->s_link) {
461                     if (scn2 == scn) {
462                         break;
463                     }
464                     end2 = scn2->s_shdr64.sh_offset;
465                     if (scn2->s_shdr64.sh_type != SHT_NOBITS) {
466                         end2 += scn2->s_shdr64.sh_size;
467                     }
468                     if (end1 > scn2->s_shdr64.sh_offset
469                      && end2 > shdr->sh_offset) {
470                         seterr(ERROR_SCN_OVERLAP);
471                         return -1;
472                     }
473                 }
474             }
475             if (off < end1) {
476                 off = end1;
477             }
478         }
479         *flag |= scn->s_shdr_flags;
480     }
481
482     if (shnum) {
483         entsize = _fsize(ELFCLASS64, version, ELF_T_SHDR);
484         elf_assert(entsize);
485         if (layout) {
486             align(off, align_addr);
487             rewrite(ehdr->e_shoff, off, elf->e_ehdr_flags);
488             off += shnum * entsize;
489         }
490         else {
491             off = max(off, ehdr->e_shoff + shnum * entsize);
492         }
493     }
494     else {
495         entsize = 0;
496         if (layout) {
497             rewrite(ehdr->e_shoff, 0, elf->e_ehdr_flags);
498         }
499     }
500     if (shnum >= SHN_LORESERVE) {
501         Elf_Scn *scn = elf->e_scn_1;
502         Elf64_Shdr *shdr = &scn->s_shdr64;
503
504         elf_assert(scn->s_index == 0);
505         rewrite(shdr->sh_size, shnum, scn->s_shdr_flags);
506         *flag |= scn->s_shdr_flags;
507         shnum = 0;
508     }
509     rewrite(ehdr->e_shnum, shnum, elf->e_ehdr_flags);
510     rewrite(ehdr->e_shentsize, entsize, elf->e_ehdr_flags);
511
512     rewrite(ehdr->e_ident[EI_MAG0], ELFMAG0, elf->e_ehdr_flags);
513     rewrite(ehdr->e_ident[EI_MAG1], ELFMAG1, elf->e_ehdr_flags);
514     rewrite(ehdr->e_ident[EI_MAG2], ELFMAG2, elf->e_ehdr_flags);
515     rewrite(ehdr->e_ident[EI_MAG3], ELFMAG3, elf->e_ehdr_flags);
516     rewrite(ehdr->e_ident[EI_CLASS], ELFCLASS64, elf->e_ehdr_flags);
517     rewrite(ehdr->e_ident[EI_DATA], encoding, elf->e_ehdr_flags);
518     rewrite(ehdr->e_ident[EI_VERSION], version, elf->e_ehdr_flags);
519     rewrite(ehdr->e_version, version, elf->e_ehdr_flags);
520
521     *flag |= elf->e_ehdr_flags;
522
523     return off;
524 }
525
526 #endif /* __LIBELF64 */
527
528 #define ptrinside(p,a,l)        ((p)>=(a)&&(p)<(a)+(l))
529 #define newptr(p,o,n)           ((p)=((p)-(o))+(n))
530
531 static int
532 _elf_update_pointers(Elf *elf, char *outbuf, size_t len) {
533     Elf_Scn *scn;
534     Scn_Data *sd;
535     char *data, *rawdata;
536
537     elf_assert(elf);
538     elf_assert(elf->e_data);
539     elf_assert(!elf->e_parent);
540     elf_assert(!elf->e_unmap_data);
541     elf_assert(elf->e_kind == ELF_K_ELF);
542     elf_assert(len >= EI_NIDENT);
543
544     /* resize memory images */
545     if (len <= elf->e_dsize) {
546         /* don't shorten the memory image */
547         data = elf->e_data;
548     }
549     else if ((data = (char*)realloc(elf->e_data, len))) {
550         elf->e_dsize = len;
551     }
552     else {
553         seterr(ERROR_IO_2BIG);
554         return -1;
555     }
556     if (elf->e_rawdata == elf->e_data) {
557         /* update frozen raw image */
558         memcpy(data, outbuf, len);
559         elf->e_data = elf->e_rawdata = data;
560         /* cooked data is stored outside the raw image */
561         return 0;
562     }
563     if (elf->e_rawdata) {
564         /* update raw image */
565         if (!(rawdata = (char*)realloc(elf->e_rawdata, len))) {
566             seterr(ERROR_IO_2BIG);
567             return -1;
568         }
569         memcpy(rawdata, outbuf, len);
570         elf->e_rawdata = rawdata;
571     }
572     if (data == elf->e_data) {
573         /* nothing more to do */
574         return 0;
575     }
576     /* adjust internal pointers */
577     for (scn = elf->e_scn_1; scn; scn = scn->s_link) {
578         elf_assert(scn->s_magic == SCN_MAGIC);
579         elf_assert(scn->s_elf == elf);
580         if ((sd = scn->s_data_1)) {
581             elf_assert(sd->sd_magic == DATA_MAGIC);
582             elf_assert(sd->sd_scn == scn);
583             if (sd->sd_memdata && !sd->sd_free_data) {
584                 elf_assert(ptrinside(sd->sd_memdata, elf->e_data, elf->e_dsize));
585                 if (sd->sd_data.d_buf == sd->sd_memdata) {
586                     newptr(sd->sd_memdata, elf->e_data, data);
587                     sd->sd_data.d_buf = sd->sd_memdata;
588                 }
589                 else {
590                     newptr(sd->sd_memdata, elf->e_data, data);
591                 }
592             }
593         }
594         if ((sd = scn->s_rawdata)) {
595             elf_assert(sd->sd_magic == DATA_MAGIC);
596             elf_assert(sd->sd_scn == scn);
597             if (sd->sd_memdata && sd->sd_free_data) {
598                 size_t off, len;
599
600                 if (elf->e_class == ELFCLASS32) {
601                     off = scn->s_shdr32.sh_offset;
602                     len = scn->s_shdr32.sh_size;
603                 }
604 #if __LIBELF64
605                 else if (elf->e_class == ELFCLASS64) {
606                     off = scn->s_shdr64.sh_offset;
607                     len = scn->s_shdr64.sh_size;
608                 }
609 #endif /* __LIBELF64 */
610                 else {
611                     seterr(ERROR_UNIMPLEMENTED);
612                     return -1;
613                 }
614                 if (!(rawdata = (char*)realloc(sd->sd_memdata, len))) {
615                     seterr(ERROR_IO_2BIG);
616                     return -1;
617                 }
618                 memcpy(rawdata, outbuf + off, len);
619                 if (sd->sd_data.d_buf == sd->sd_memdata) {
620                     sd->sd_data.d_buf = rawdata;
621                 }
622                 sd->sd_memdata = rawdata;
623             }
624         }
625     }
626     elf->e_data = data;
627     return 0;
628 }
629
630 #undef ptrinside
631 #undef newptr
632
633 static off_t
634 _elf32_write(Elf *elf, char *outbuf, size_t len) {
635     Elf32_Ehdr *ehdr;
636     Elf32_Shdr *shdr;
637     Elf_Scn *scn;
638     Scn_Data *sd;
639     Elf_Data src;
640     Elf_Data dst;
641     unsigned encode;
642
643     elf_assert(len);
644     elf_assert(elf->e_ehdr);
645     ehdr = (Elf32_Ehdr*)elf->e_ehdr;
646     encode = ehdr->e_ident[EI_DATA];
647
648     src.d_buf = ehdr;
649     src.d_type = ELF_T_EHDR;
650     src.d_size = _msize(ELFCLASS32, _elf_version, ELF_T_EHDR);
651     src.d_version = _elf_version;
652     dst.d_buf = outbuf;
653     dst.d_size = ehdr->e_ehsize;
654     dst.d_version = ehdr->e_version;
655     if (!elf32_xlatetof(&dst, &src, encode)) {
656         return -1;
657     }
658
659     if (elf->e_phnum) {
660         src.d_buf = elf->e_phdr;
661         src.d_type = ELF_T_PHDR;
662         src.d_size = elf->e_phnum * _msize(ELFCLASS32, _elf_version, ELF_T_PHDR);
663         src.d_version = _elf_version;
664         dst.d_buf = outbuf + ehdr->e_phoff;
665         dst.d_size = elf->e_phnum * ehdr->e_phentsize;
666         dst.d_version = ehdr->e_version;
667         if (!elf32_xlatetof(&dst, &src, encode)) {
668             return -1;
669         }
670     }
671
672     for (scn = elf->e_scn_1; scn; scn = scn->s_link) {
673         elf_assert(scn->s_magic == SCN_MAGIC);
674         elf_assert(scn->s_elf == elf);
675
676         src.d_buf = &scn->s_uhdr;
677         src.d_type = ELF_T_SHDR;
678         src.d_size = _msize(ELFCLASS32, EV_CURRENT, ELF_T_SHDR);
679         src.d_version = EV_CURRENT;
680         dst.d_buf = outbuf + ehdr->e_shoff + scn->s_index * ehdr->e_shentsize;
681         dst.d_size = ehdr->e_shentsize;
682         dst.d_version = ehdr->e_version;
683         if (!elf32_xlatetof(&dst, &src, encode)) {
684             return -1;
685         }
686
687         if (scn->s_index == SHN_UNDEF) {
688             continue;
689         }
690         shdr = &scn->s_shdr32;
691         if (shdr->sh_type == SHT_NULL || shdr->sh_type == SHT_NOBITS) {
692             continue;
693         }
694         /* XXX: this is probably no longer necessary */
695         if (scn->s_data_1 && !elf_getdata(scn, NULL)) {
696             return -1;
697         }
698         for (sd = scn->s_data_1; sd; sd = sd->sd_link) {
699             elf_assert(sd->sd_magic == DATA_MAGIC);
700             elf_assert(sd->sd_scn == scn);
701             src = sd->sd_data;
702             if (!src.d_size) {
703                 continue;
704             }
705             if (!src.d_buf) {
706                 seterr(ERROR_NULLBUF);
707                 return -1;
708             }
709             dst.d_buf = outbuf + shdr->sh_offset + src.d_off;
710             dst.d_size = src.d_size;
711             dst.d_version = ehdr->e_version;
712             if (valid_type(src.d_type)) {
713                 size_t tmp;
714
715                 tmp = _elf32_xltsize(&src, dst.d_version, ELFDATA2LSB, 1);
716                 if (tmp == (size_t)-1) {
717                     return -1;
718                 }
719                 dst.d_size = tmp;
720             }
721             else {
722                 src.d_type = ELF_T_BYTE;
723             }
724             if (!elf32_xlatetof(&dst, &src, encode)) {
725                 return -1;
726             }
727         }
728     }
729
730     /* cleanup */
731     if (elf->e_readable && _elf_update_pointers(elf, outbuf, len)) {
732         return -1;
733     }
734     /* NOTE: ehdr is no longer valid! */
735     ehdr = (Elf32_Ehdr*)elf->e_ehdr; elf_assert(ehdr);
736     elf->e_encoding = ehdr->e_ident[EI_DATA];
737     elf->e_version = ehdr->e_ident[EI_VERSION];
738     elf->e_elf_flags &= ~ELF_F_DIRTY;
739     elf->e_ehdr_flags &= ~ELF_F_DIRTY;
740     elf->e_phdr_flags &= ~ELF_F_DIRTY;
741     for (scn = elf->e_scn_1; scn; scn = scn->s_link) {
742         scn->s_scn_flags &= ~ELF_F_DIRTY;
743         scn->s_shdr_flags &= ~ELF_F_DIRTY;
744         for (sd = scn->s_data_1; sd; sd = sd->sd_link) {
745             sd->sd_data_flags &= ~ELF_F_DIRTY;
746         }
747         if (elf->e_readable) {
748             shdr = &scn->s_shdr32;
749             scn->s_type = shdr->sh_type;
750             scn->s_size = shdr->sh_size;
751             scn->s_offset = shdr->sh_offset;
752         }
753     }
754     elf->e_size = len;
755     return len;
756 }
757
758 #if __LIBELF64
759
760 static off_t
761 _elf64_write(Elf *elf, char *outbuf, size_t len) {
762     Elf64_Ehdr *ehdr;
763     Elf64_Shdr *shdr;
764     Elf_Scn *scn;
765     Scn_Data *sd;
766     Elf_Data src;
767     Elf_Data dst;
768     unsigned encode;
769
770     elf_assert(len);
771     elf_assert(elf->e_ehdr);
772     ehdr = (Elf64_Ehdr*)elf->e_ehdr;
773     encode = ehdr->e_ident[EI_DATA];
774
775     src.d_buf = ehdr;
776     src.d_type = ELF_T_EHDR;
777     src.d_size = _msize(ELFCLASS64, _elf_version, ELF_T_EHDR);
778     src.d_version = _elf_version;
779     dst.d_buf = outbuf;
780     dst.d_size = ehdr->e_ehsize;
781     dst.d_version = ehdr->e_version;
782     if (!elf64_xlatetof(&dst, &src, encode)) {
783         return -1;
784     }
785
786     if (elf->e_phnum) {
787         src.d_buf = elf->e_phdr;
788         src.d_type = ELF_T_PHDR;
789         src.d_size = elf->e_phnum * _msize(ELFCLASS64, _elf_version, ELF_T_PHDR);
790         src.d_version = _elf_version;
791         dst.d_buf = outbuf + ehdr->e_phoff;
792         dst.d_size = elf->e_phnum * ehdr->e_phentsize;
793         dst.d_version = ehdr->e_version;
794         if (!elf64_xlatetof(&dst, &src, encode)) {
795             return -1;
796         }
797     }
798
799     for (scn = elf->e_scn_1; scn; scn = scn->s_link) {
800         elf_assert(scn->s_magic == SCN_MAGIC);
801         elf_assert(scn->s_elf == elf);
802
803         src.d_buf = &scn->s_uhdr;
804         src.d_type = ELF_T_SHDR;
805         src.d_size = _msize(ELFCLASS64, EV_CURRENT, ELF_T_SHDR);
806         src.d_version = EV_CURRENT;
807         dst.d_buf = outbuf + ehdr->e_shoff + scn->s_index * ehdr->e_shentsize;
808         dst.d_size = ehdr->e_shentsize;
809         dst.d_version = ehdr->e_version;
810         if (!elf64_xlatetof(&dst, &src, encode)) {
811             return -1;
812         }
813
814         if (scn->s_index == SHN_UNDEF) {
815             continue;
816         }
817         shdr = &scn->s_shdr64;
818         if (shdr->sh_type == SHT_NULL || shdr->sh_type == SHT_NOBITS) {
819             continue;
820         }
821         /* XXX: this is probably no longer necessary */
822         if (scn->s_data_1 && !elf_getdata(scn, NULL)) {
823             return -1;
824         }
825         for (sd = scn->s_data_1; sd; sd = sd->sd_link) {
826             elf_assert(sd->sd_magic == DATA_MAGIC);
827             elf_assert(sd->sd_scn == scn);
828             src = sd->sd_data;
829             if (!src.d_size) {
830                 continue;
831             }
832             if (!src.d_buf) {
833                 seterr(ERROR_NULLBUF);
834                 return -1;
835             }
836             dst.d_buf = outbuf + shdr->sh_offset + src.d_off;
837             dst.d_size = src.d_size;
838             dst.d_version = ehdr->e_version;
839             if (valid_type(src.d_type)) {
840                 size_t tmp;
841
842                 tmp = _elf64_xltsize(&src, dst.d_version, ELFDATA2LSB, 1);
843                 if (tmp == (size_t)-1) {
844                     return -1;
845                 }
846                 dst.d_size = tmp;
847             }
848             else {
849                 src.d_type = ELF_T_BYTE;
850             }
851             if (!elf64_xlatetof(&dst, &src, encode)) {
852                 return -1;
853             }
854         }
855     }
856
857     /* cleanup */
858     if (elf->e_readable && _elf_update_pointers(elf, outbuf, len)) {
859         return -1;
860     }
861     /* NOTE: ehdr is no longer valid! */
862     ehdr = (Elf64_Ehdr*)elf->e_ehdr; elf_assert(ehdr);
863     elf->e_encoding = ehdr->e_ident[EI_DATA];
864     elf->e_version = ehdr->e_ident[EI_VERSION];
865     elf->e_elf_flags &= ~ELF_F_DIRTY;
866     elf->e_ehdr_flags &= ~ELF_F_DIRTY;
867     elf->e_phdr_flags &= ~ELF_F_DIRTY;
868     for (scn = elf->e_scn_1; scn; scn = scn->s_link) {
869         scn->s_scn_flags &= ~ELF_F_DIRTY;
870         scn->s_shdr_flags &= ~ELF_F_DIRTY;
871         for (sd = scn->s_data_1; sd; sd = sd->sd_link) {
872             sd->sd_data_flags &= ~ELF_F_DIRTY;
873         }
874         if (elf->e_readable) {
875             shdr = &scn->s_shdr64;
876             scn->s_type = shdr->sh_type;
877             scn->s_size = shdr->sh_size;
878             scn->s_offset = shdr->sh_offset;
879         }
880     }
881     elf->e_size = len;
882     return len;
883 }
884
885 #endif /* __LIBELF64 */
886
887 static int
888 xwrite(int fd, char *buffer, size_t len) {
889     size_t done = 0;
890     size_t n;
891
892     while (done < len) {
893         n = write(fd, buffer + done, len - done);
894         if (n == 0) {
895             /* file system full */
896             return -1;
897         }
898         else if (n != (size_t)-1) {
899             /* some bytes written, continue */
900             done += n;
901         }
902         else if (errno != EAGAIN && errno != EINTR) {
903             /* real error */
904             return -1;
905         }
906     }
907     return 0;
908 }
909
910 static off_t
911 _elf_output(Elf *elf, int fd, size_t len, off_t (*_elf_write)(Elf*, char*, size_t)) {
912     char *buf;
913     off_t err;
914
915     elf_assert(len);
916 #if HAVE_FTRUNCATE
917     ftruncate(fd, 0);
918 #endif /* HAVE_FTRUNCATE */
919 #if HAVE_MMAP
920     /*
921      * Make sure the file is (at least) len bytes long
922      */
923 #if HAVE_FTRUNCATE
924     lseek(fd, (off_t)len, SEEK_SET);
925     if (ftruncate(fd, len)) {
926 #else /* HAVE_FTRUNCATE */
927     {
928 #endif /* HAVE_FTRUNCATE */
929         if (lseek(fd, (off_t)len - 1, SEEK_SET) != (off_t)len - 1) {
930             seterr(ERROR_IO_SEEK);
931             return -1;
932         }
933         if (xwrite(fd, "", 1)) {
934             seterr(ERROR_IO_WRITE);
935             return -1;
936         }
937     }
938     buf = (void*)mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
939     if (buf != (char*)-1) {
940         if ((char)_elf_fill && !(elf->e_elf_flags & ELF_F_LAYOUT)) {
941             memset(buf, _elf_fill, len);
942         }
943         err = _elf_write(elf, buf, len);
944         munmap(buf, len);
945         return err;
946     }
947 #endif /* HAVE_MMAP */
948     if (!(buf = (char*)malloc(len))) {
949         seterr(ERROR_MEM_OUTBUF);
950         return -1;
951     }
952     memset(buf, _elf_fill, len);
953     err = _elf_write(elf, buf, len);
954     if (err != -1 && (size_t)err == len) {
955         if (lseek(fd, (off_t)0, SEEK_SET)) {
956             seterr(ERROR_IO_SEEK);
957             err = -1;
958         }
959         else if (xwrite(fd, buf, len)) {
960             seterr(ERROR_IO_WRITE);
961             err = -1;
962         }
963     }
964     free(buf);
965     return err;
966 }
967
968 off_t
969 elf_update(Elf *elf, Elf_Cmd cmd) {
970     unsigned flag;
971     off_t len;
972
973     if (!elf) {
974         return -1;
975     }
976     elf_assert(elf->e_magic == ELF_MAGIC);
977     if (cmd == ELF_C_WRITE) {
978         if (!elf->e_writable) {
979             seterr(ERROR_RDONLY);
980             return -1;
981         }
982         if (elf->e_disabled) {
983             seterr(ERROR_FDDISABLED);
984             return -1;
985         }
986     }
987     else if (cmd != ELF_C_NULL) {
988         seterr(ERROR_INVALID_CMD);
989         return -1;
990     }
991
992     if (!elf->e_ehdr) {
993         seterr(ERROR_NOEHDR);
994     }
995     else if (elf->e_kind != ELF_K_ELF) {
996         seterr(ERROR_NOTELF);
997     }
998     else if (elf->e_class == ELFCLASS32) {
999         len = _elf32_layout(elf, &flag);
1000         if (len != -1 && cmd == ELF_C_WRITE && (flag & ELF_F_DIRTY)) {
1001             len = _elf_output(elf, elf->e_fd, (size_t)len, _elf32_write);
1002         }
1003         return len;
1004     }
1005 #if __LIBELF64
1006     else if (elf->e_class == ELFCLASS64) {
1007         len = _elf64_layout(elf, &flag);
1008         if (len != -1 && cmd == ELF_C_WRITE && (flag & ELF_F_DIRTY)) {
1009             len = _elf_output(elf, elf->e_fd, (size_t)len, _elf64_write);
1010         }
1011         return len;
1012     }
1013 #endif /* __LIBELF64 */
1014     else if (valid_class(elf->e_class)) {
1015         seterr(ERROR_UNIMPLEMENTED);
1016     }
1017     else {
1018         seterr(ERROR_UNKNOWN_CLASS);
1019     }
1020     return -1;
1021 }