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