2 * Copyright (c) 1997 John D. Polstra.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/types.h>
30 #include "../../alpha/include/elf.h"
38 #define HASHSIZE 1009u /* Number of hash chains. */
39 #define PREFIX ".set." /* Section name prefix for linker sets. */
41 /* One entry in the hash table. */
42 typedef struct hashent {
43 struct hashent *next; /* Next entry with the same hash. */
44 char *name; /* Name of the linker set. */
45 size_t size; /* Size in bytes. */
48 /* Allocate storage for "count" objects of type "type". */
49 #define NEW(type, count) ((type *) xmalloc((count) * sizeof(type)))
51 static hashent *hashtab[HASHSIZE]; /* Hash chain heads. */
53 static void enter(const char *, size_t);
54 static int enter_sets(const char *);
55 static unsigned int hash(const char *);
56 static hashent *merge(void);
57 static int my_byte_order(void);
58 static void *xmalloc(size_t);
59 static char *xstrdup(const char *);
62 * This is a special-purpose program to generate the linker set definitions
63 * needed when building an ELF kernel. Its arguments are the names of
64 * ELF object files. It scans the section names of the object files,
65 * building a table of those that begin with ".set.", which represent
66 * linker sets. Finally, for each set "foo" with "count" elements, it
67 * writes a line "DEFINE_SET(foo, count);" to the standard output.
70 main(int argc, char **argv)
73 int status = EXIT_SUCCESS;
76 for (i = 1; i < argc; i++)
77 if (enter_sets(argv[i]) == -1)
78 status = EXIT_FAILURE;
81 while (list != NULL) {
84 printf("DEFINE_SET(%s, %lu);\n", list->name,
85 (unsigned long) (list->size / sizeof (void *)));
96 * Enter the given string into the hash table, if it is not already there.
97 * Each hash chain is kept sorted, so that it will be easy to merge the
98 * chains to get a single sorted list.
101 enter(const char *name, size_t size)
108 linkp = &hashtab[hash(name) % HASHSIZE];
109 while ((entp = *linkp) != NULL && (c = strcmp(name, entp->name)) > 0)
112 if (entp == NULL || c != 0) { /* Not found; create a new entry. */
113 newp = NEW(hashent, 1);
114 newp->name = xstrdup(name);
125 * Return a hash value for the given string.
133 while((ch = *s) != '\0') {
141 * Enter the linker sets from the given ELF object file. Returns 0 on
142 * success, or -1 if an error occurred.
145 enter_sets(const char *filename)
153 if ((iop = fopen(filename, "rb")) == NULL) {
154 warn("%s", filename);
157 if (fread(&ehdr, sizeof ehdr, 1, iop) != 1 ||
158 ehdr.e_ident[EI_MAG0] != ELFMAG0 ||
159 ehdr.e_ident[EI_MAG1] != ELFMAG1 ||
160 ehdr.e_ident[EI_MAG2] != ELFMAG2 ||
161 ehdr.e_ident[EI_MAG3] != ELFMAG3) {
162 warnx("%s: not an ELF file", filename);
166 if (ehdr.e_ident[EI_VERSION] != EV_CURRENT) {
167 warnx("%s: unsupported ELF version", filename);
171 if (ehdr.e_ident[EI_DATA] != my_byte_order()) {
172 warnx("%s: unsupported byte order", filename);
176 if (ehdr.e_shoff == 0) {
177 warnx("%s: no section table", filename);
181 if (ehdr.e_shstrndx == SHN_UNDEF) {
182 warnx("%s: no section name string table", filename);
187 shdr = NEW(Elf64_Shdr, ehdr.e_shnum);
188 if (fseek(iop, ehdr.e_shoff, SEEK_SET) == -1) {
189 warn("%s", filename);
194 if (fread(shdr, sizeof *shdr, ehdr.e_shnum, iop) != ehdr.e_shnum) {
195 warnx("%s: truncated section table", filename);
201 shstr = NEW(char, shdr[ehdr.e_shstrndx].sh_size);
202 if (fseek(iop, shdr[ehdr.e_shstrndx].sh_offset, SEEK_SET) == -1) {
203 warn("%s", filename);
209 if (fread(shstr, sizeof *shstr, shdr[ehdr.e_shstrndx].sh_size, iop) !=
210 shdr[ehdr.e_shstrndx].sh_size) {
211 warnx("%s: truncated section name string table", filename);
218 for (i = 1; i < ehdr.e_shnum; i++) {
219 const char *name = shstr + shdr[i].sh_name;
221 if (strncmp(name, PREFIX, sizeof (PREFIX) - 1) == 0)
222 enter(name + sizeof (PREFIX) - 1, shdr[i].sh_size);
232 * Destructively merge all the sorted hash chains into a single sorted
233 * list, and return a pointer to its first element.
238 unsigned int numchains = HASHSIZE;
240 while (numchains > 1) { /* More merging to do. */
243 * Merge chains pairwise from the outside in, halving the
246 while (numchains - lo >= 2) {
247 hashent **linkp = &hashtab[lo];
248 hashent *l1 = hashtab[lo++];
249 hashent *l2 = hashtab[--numchains];
251 while (l1 != NULL && l2 != NULL) {
252 if (strcmp(l1->name, l2->name) < 0) {
262 *linkp = l1==NULL ? l2 : l1;
270 * Determine the host byte order.
275 static unsigned short s = 0xbbaa;
278 byte0 = *(unsigned char *)&s;
280 return (ELFDATA2LSB);
281 else if (byte0 == 0xbb)
282 return (ELFDATA2MSB);
284 return (ELFDATANONE);
288 * Allocate a chunk of memory and return a pointer to it. Die if the
298 err(EXIT_FAILURE, "malloc");
303 * Duplicate a string and return a pointer to the copy. Die if there is
307 xstrdup(const char *s)
311 size = strlen(s) + 1;
312 return (memcpy(xmalloc(size), s, size));