xref: /illumos-gate/usr/src/cmd/sgs/libelf/common/checksum.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 /*	Copyright (c) 1987, 1988 Microsoft Corporation	*/
31 /*	  All Rights Reserved	*/
32 
33 #pragma ident	"%Z%%M%	%I%	%E% SMI"
34 
35 #include "syn.h"
36 #include <errno.h>
37 #include <libelf.h>
38 #include "decl.h"
39 #include "msg.h"
40 
41 /*
42  * Routines for generating a checksum for an elf image. Typically used to create
43  * a DT_CHECKSUM entry.  This checksum is intended to remain constant after
44  * operations such as strip(1)/mcs(1), thus only allocatable sections are
45  * processed, and of those, any that might be modified by these external
46  * commands are skipped.
47  */
48 #define	MSW(l)	(((l) >> 16) & 0x0000ffffL)
49 #define	LSW(l)	((l) & 0x0000ffffL)
50 
51 
52 /*
53  * update and epilogue sum functions (stolen from libcmd)
54  */
55 static long
56 sumupd(long sum, char *cp, unsigned long cnt)
57 {
58 	if ((cp == 0) || (cnt == 0))
59 		return (sum);
60 
61 	while (cnt--)
62 		sum += *cp++ & 0x00ff;
63 
64 	return (sum);
65 }
66 
67 static long
68 sumepi(long sum)
69 {
70 	long	_sum;
71 
72 	_sum = LSW(sum) + MSW(sum);
73 	return ((ushort_t)(LSW(_sum) + MSW(_sum)));
74 }
75 
76 long
77 elf32_checksum(Elf * elf)
78 {
79 	long		sum = 0;
80 	Elf32_Ehdr *	ehdr;
81 	Elf32_Shdr *	shdr;
82 	Elf_Scn *	scn;
83 	Elf_Data *	data, * (* getdata)(Elf_Scn *, Elf_Data *);
84 	size_t		shnum;
85 
86 	if ((ehdr = elf32_getehdr(elf)) == 0)
87 		return (0);
88 
89 	/*
90 	 * Determine the data information to retrieve.  When called from ld()
91 	 * we're processing an ELF_C_IMAGE (memory) image and thus need to use
92 	 * elf_getdata(), as there is not yet a file image (or raw data) backing
93 	 * this.  When called from utilities like elfdump(1) we're processing a
94 	 * file image and thus using the elf_rawdata() allows the same byte
95 	 * stream to be processed from different architectures - presently this
96 	 * is irrelevant, as the checksum simply sums the data bytes, their
97 	 * order doesn't matter.  But being uncooked is slightly less overhead.
98 	 */
99 	if (elf->ed_myflags & EDF_MEMORY)
100 		getdata = elf_getdata;
101 	else
102 		getdata = elf_rawdata;
103 
104 	for (shnum = 1; shnum < ehdr->e_shnum; shnum++) {
105 		if ((scn = elf_getscn(elf, shnum)) == 0)
106 			return (0);
107 		if ((shdr = elf32_getshdr(scn)) == 0)
108 			return (0);
109 
110 		if (!(shdr->sh_flags & SHF_ALLOC))
111 			continue;
112 
113 		if ((shdr->sh_type == SHT_DYNSYM) ||
114 		    (shdr->sh_type == SHT_DYNAMIC))
115 			continue;
116 
117 		data = 0;
118 		while ((data = (*getdata)(scn, data)) != 0)
119 			sum = sumupd(sum, data->d_buf, data->d_size);
120 
121 	}
122 	return (sumepi(sum));
123 }
124 
125 long
126 elf64_checksum(Elf * elf)
127 {
128 	long		sum = 0;
129 	Elf64_Ehdr *	ehdr;
130 	Elf64_Shdr *	shdr;
131 	Elf_Scn *	scn;
132 	Elf_Data *	data;
133 	size_t		shnum;
134 
135 	if ((ehdr = elf64_getehdr(elf)) == 0)
136 		return (0);
137 
138 	for (shnum = 1; shnum < ehdr->e_shnum; shnum++) {
139 		if ((scn = elf_getscn(elf, shnum)) == 0)
140 			return (0);
141 		if ((shdr = elf64_getshdr(scn)) == 0)
142 			return (0);
143 
144 		if (!(shdr->sh_flags & SHF_ALLOC))
145 			continue;
146 
147 		if ((shdr->sh_type == SHT_DYNSYM) ||
148 		    (shdr->sh_type == SHT_DYNAMIC))
149 			continue;
150 
151 		data = 0;
152 		while ((data = elf_getdata(scn, data)) != 0)
153 			sum = sumupd(sum, data->d_buf, data->d_size);
154 
155 	}
156 	return (sumepi(sum));
157 }
158