tools/elf4rom/libs/libelf-0.8.10/lib/checksum.c
changeset 34 92d87f2e53c2
equal deleted inserted replaced
33:1af5c1be89f8 34:92d87f2e53c2
       
     1 /*
       
     2 checksum.c - implementation of the elf{32,64}_checksum(3) functions.
       
     3 Copyright (C) 1995 - 2001 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: checksum.c,v 1.6 2005/05/21 15:39:20 michael Exp $";
       
    24 #endif /* lint */
       
    25 
       
    26 /*
       
    27  * Compatibility note:
       
    28  *
       
    29  * The algorithm used in {elf32,elf64,gelf}_checksum() does not seem to
       
    30  * be documented.  I hope I got it right.  My implementation does the
       
    31  * following:
       
    32  *
       
    33  *   - skip sections that do not have the SHF_ALLOC flag set
       
    34  *   - skip sections of type SHT_NULL, SHT_NOBITS, SHT_DYNSYM and
       
    35  *     SHT_DYNAMIC
       
    36  *   - add all data bytes from the remaining sections, modulo 2**32
       
    37  *   - add upper and lower half of the result
       
    38  *   - subtract 0xffff if the result is > 0xffff
       
    39  *   - if any error occurs, return 0L
       
    40  */
       
    41 
       
    42 static int
       
    43 skip_section(Elf_Scn *scn, unsigned cls) {
       
    44     if (cls == ELFCLASS32) {
       
    45 	Elf32_Shdr *shdr = &scn->s_shdr32;
       
    46 
       
    47 	if (!(shdr->sh_flags & SHF_ALLOC)) {
       
    48 	    return 1;
       
    49 	}
       
    50 	switch (shdr->sh_type) {
       
    51 	    case SHT_NULL:
       
    52 	    case SHT_NOBITS:
       
    53 	    /* Solaris seems to ignore these, too */
       
    54 	    case SHT_DYNSYM:
       
    55 	    case SHT_DYNAMIC:
       
    56 		return 1;
       
    57 	}
       
    58     }
       
    59 #if __LIBELF64
       
    60     else if (cls == ELFCLASS64) {
       
    61 	Elf64_Shdr *shdr = &scn->s_shdr64;
       
    62 
       
    63 	if (!(shdr->sh_flags & SHF_ALLOC)) {
       
    64 	    return 1;
       
    65 	}
       
    66 	switch (shdr->sh_type) {
       
    67 	    case SHT_NULL:
       
    68 	    case SHT_NOBITS:
       
    69 	    /* Solaris seems to ignore these, too */
       
    70 	    case SHT_DYNSYM:
       
    71 	    case SHT_DYNAMIC:
       
    72 		return 1;
       
    73 	}
       
    74     }
       
    75 #endif /* __LIBELF64 */
       
    76     else {
       
    77 	seterr(ERROR_UNIMPLEMENTED);
       
    78     }
       
    79     return 0;
       
    80 }
       
    81 
       
    82 static long
       
    83 add_bytes(unsigned char *ptr, size_t len) {
       
    84     long csum = 0;
       
    85 
       
    86     while (len--) {
       
    87 	csum += *ptr++;
       
    88     }
       
    89     return csum;
       
    90 }
       
    91 
       
    92 static long
       
    93 _elf_csum(Elf *elf) {
       
    94     long csum = 0;
       
    95     Elf_Data *data;
       
    96     Elf_Scn *scn;
       
    97 
       
    98     if (!elf->e_ehdr && !_elf_cook(elf)) {
       
    99 	/* propagate errors from _elf_cook */
       
   100 	return 0L;
       
   101     }
       
   102     seterr(0);
       
   103     for (scn = elf->e_scn_1; scn; scn = scn->s_link) {
       
   104 	if (scn->s_index == SHN_UNDEF || skip_section(scn, elf->e_class)) {
       
   105 	    continue;
       
   106 	}
       
   107 	data = NULL;
       
   108 	while ((data = elf_getdata(scn, data))) {
       
   109 	    if (data->d_size) {
       
   110 		if (data->d_buf == NULL) {
       
   111 		    seterr(ERROR_NULLBUF);
       
   112 		    return 0L;
       
   113 		}
       
   114 		csum += add_bytes(data->d_buf, data->d_size);
       
   115 	    }
       
   116 	}
       
   117     }
       
   118     if (_elf_errno) {
       
   119 	return 0L;
       
   120     }
       
   121     csum = (csum & 0xffff) + ((csum >> 16) & 0xffff);
       
   122     if (csum > 0xffff) {
       
   123 	csum -= 0xffff;
       
   124     }
       
   125     return csum;
       
   126 }
       
   127 
       
   128 long
       
   129 elf32_checksum(Elf *elf) {
       
   130     if (elf) {
       
   131 	if (elf->e_kind != ELF_K_ELF) {
       
   132 	    seterr(ERROR_NOTELF);
       
   133 	}
       
   134 	else if (elf->e_class != ELFCLASS32) {
       
   135 	    seterr(ERROR_CLASSMISMATCH);
       
   136 	}
       
   137 	else {
       
   138 	    return _elf_csum(elf);
       
   139 	}
       
   140     }
       
   141     return 0L;
       
   142 }
       
   143 
       
   144 #if __LIBELF64
       
   145 
       
   146 long
       
   147 elf64_checksum(Elf *elf) {
       
   148     if (elf) {
       
   149 	if (elf->e_kind != ELF_K_ELF) {
       
   150 	    seterr(ERROR_NOTELF);
       
   151 	}
       
   152 	else if (elf->e_class != ELFCLASS64) {
       
   153 	    seterr(ERROR_CLASSMISMATCH);
       
   154 	}
       
   155 	else {
       
   156 	    return _elf_csum(elf);
       
   157 	}
       
   158     }
       
   159     return 0L;
       
   160 }
       
   161 
       
   162 long
       
   163 gelf_checksum(Elf *elf) {
       
   164     if (elf) {
       
   165 	if (elf->e_kind != ELF_K_ELF) {
       
   166 	    seterr(ERROR_NOTELF);
       
   167 	}
       
   168 	else if (!valid_class(elf->e_class)) {
       
   169 	    seterr(ERROR_UNKNOWN_CLASS);
       
   170 	}
       
   171 	else {
       
   172 	    return _elf_csum(elf);
       
   173 	}
       
   174     }
       
   175     return 0L;
       
   176 }
       
   177 
       
   178 #endif /* __LIBELF64 */