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
26 * $FreeBSD: src/usr.bin/gensetdefs/gensetdefs.c,v 1.4 1999/12/12 21:16:46 marcel Exp $
29 #include <sys/types.h>
30 #if defined(arch_i386)
31 #define __ELF_WORD_SIZE 32
32 #include <sys/elf32.h>
33 #elif defined(arch_alpha)
34 #define __ELF_WORD_SIZE 64
35 #include <sys/elf64.h>
37 #include <sys/elf_generic.h>
45 #define HASHSIZE 1009u /* Number of hash chains. */
46 #define PREFIX ".set." /* Section name prefix for linker sets. */
48 /* One entry in the hash table. */
49 typedef struct hashent {
50 struct hashent *next; /* Next entry with the same hash. */
51 char *name; /* Name of the linker set. */
52 size_t size; /* Size in bytes. */
55 /* Allocate storage for "count" objects of type "type". */
56 #define NEW(type, count) ((type *) xmalloc((count) * sizeof(type)))
58 static hashent *hashtab[HASHSIZE]; /* Hash chain heads. */
60 static void enter(const char *, size_t);
61 static int enter_sets(const char *);
62 static unsigned int hash(const char *);
63 static hashent *merge(void);
64 static int my_byte_order(void);
65 static void *xmalloc(size_t);
66 static char *xstrdup(const char *);
69 * This is a special-purpose program to generate the linker set definitions
70 * needed when building an ELF kernel. Its arguments are the names of
71 * ELF object files. It scans the section names of the object files,
72 * building a table of those that begin with ".set.", which represent
73 * linker sets. Finally, for each set "foo" with "count" elements, it
74 * writes a line "DEFINE_SET(foo, count);" to the standard output.
77 main(int argc, char **argv)
80 int status = EXIT_SUCCESS;
86 for (i = 1; i < argc; i++)
87 if (enter_sets(argv[i]) == -1)
88 status = EXIT_FAILURE;
90 fp = fopen("setdefs.h", "w");
94 while (list != NULL) {
97 fprintf(fp, "DEFINE_SET(%s, %lu);\n", list->name,
98 (unsigned long) (list->size / sizeof (void *)));
106 #if defined(arch_i386)
109 #elif defined(arch_alpha)
114 errx(1, "unknown architecture");
116 fp = fopen("setdef0.c", "w");
120 fprintf(fp, "/* THIS FILE IS GENERATED, DO NOT EDIT. */\n\n");
122 #define DEFINE_SET(set, count) \\\n\
123 __asm__(\".section .set.\" #set \",\\\"aw\\\"\"); \\\n\
124 __asm__(\".globl \" #set); \\\n\
125 __asm__(\".type \" #set \",@object\"); \\\n\
126 __asm__(\".p2align %d\"); \\\n\
127 __asm__(#set \":\"); \\\n\
128 __asm__(\".%s \" #count); \\\n\
129 __asm__(\".previous\")\n\
131 #include \"setdefs.h\" /* Contains a `DEFINE_SET' for each set */\n\
136 fp = fopen("setdef1.c", "w");
140 fprintf(fp, "/* THIS FILE IS GENERATED, DO NOT EDIT. */\n\n");
142 #define DEFINE_SET(set, count) \\\n\
143 __asm__(\".section .set.\" #set \",\\\"aw\\\"\"); \\\n\
144 __asm__(\".%s 0\"); \\\n\
145 __asm__(\".previous\")\n\
147 #include \"setdefs.h\" /* Contains a `DEFINE_SET' for each set */\n\
156 * Enter the given string into the hash table, if it is not already there.
157 * Each hash chain is kept sorted, so that it will be easy to merge the
158 * chains to get a single sorted list.
161 enter(const char *name, size_t size)
168 linkp = &hashtab[hash(name) % HASHSIZE];
169 while ((entp = *linkp) != NULL && (c = strcmp(name, entp->name)) > 0)
172 if (entp == NULL || c != 0) { /* Not found; create a new entry. */
173 newp = NEW(hashent, 1);
174 newp->name = xstrdup(name);
185 * Return a hash value for the given string.
193 while((ch = *s) != '\0') {
201 * Enter the linker sets from the given ELF object file. Returns 0 on
202 * success, or -1 if an error occurred.
205 enter_sets(const char *filename)
213 if ((iop = fopen(filename, "rb")) == NULL) {
214 warn("%s", filename);
217 if (fread(&ehdr, sizeof ehdr, 1, iop) != 1 ||
218 ehdr.e_ident[EI_MAG0] != ELFMAG0 ||
219 ehdr.e_ident[EI_MAG1] != ELFMAG1 ||
220 ehdr.e_ident[EI_MAG2] != ELFMAG2 ||
221 ehdr.e_ident[EI_MAG3] != ELFMAG3) {
222 warnx("%s: not an ELF file", filename);
226 if (ehdr.e_ident[EI_VERSION] != EV_CURRENT) {
227 warnx("%s: unsupported ELF version", filename);
231 if (ehdr.e_ident[EI_DATA] != my_byte_order()) {
232 warnx("%s: unsupported byte order", filename);
236 if (ehdr.e_shoff == 0) {
237 warnx("%s: no section table", filename);
241 if (ehdr.e_shstrndx == SHN_UNDEF) {
242 warnx("%s: no section name string table", filename);
247 shdr = NEW(Elf_Shdr, ehdr.e_shnum);
248 if (fseek(iop, ehdr.e_shoff, SEEK_SET) == -1) {
249 warn("%s", filename);
254 if (fread(shdr, sizeof *shdr, ehdr.e_shnum, iop) != ehdr.e_shnum) {
255 warnx("%s: truncated section table", filename);
261 shstr = NEW(char, shdr[ehdr.e_shstrndx].sh_size);
262 if (fseek(iop, shdr[ehdr.e_shstrndx].sh_offset, SEEK_SET) == -1) {
263 warn("%s", filename);
269 if (fread(shstr, sizeof *shstr, shdr[ehdr.e_shstrndx].sh_size, iop) !=
270 shdr[ehdr.e_shstrndx].sh_size) {
271 warnx("%s: truncated section name string table", filename);
278 for (i = 1; i < ehdr.e_shnum; i++) {
279 const char *name = shstr + shdr[i].sh_name;
281 if (strncmp(name, PREFIX, sizeof (PREFIX) - 1) == 0)
282 enter(name + sizeof (PREFIX) - 1, shdr[i].sh_size);
292 * Destructively merge all the sorted hash chains into a single sorted
293 * list, and return a pointer to its first element.
298 unsigned int numchains = HASHSIZE;
300 while (numchains > 1) { /* More merging to do. */
303 * Merge chains pairwise from the outside in, halving the
306 while (numchains - lo >= 2) {
307 hashent **linkp = &hashtab[lo];
308 hashent *l1 = hashtab[lo++];
309 hashent *l2 = hashtab[--numchains];
311 while (l1 != NULL && l2 != NULL) {
312 if (strcmp(l1->name, l2->name) < 0) {
322 *linkp = l1==NULL ? l2 : l1;
330 * Determine the host byte order.
335 static unsigned short s = 0xbbaa;
338 byte0 = *(unsigned char *)&s;
340 return (ELFDATA2LSB);
341 else if (byte0 == 0xbb)
342 return (ELFDATA2MSB);
344 return (ELFDATANONE);
348 * Allocate a chunk of memory and return a pointer to it. Die if the
358 err(EXIT_FAILURE, "malloc");
363 * Duplicate a string and return a pointer to the copy. Die if there is
367 xstrdup(const char *s)
371 size = strlen(s) + 1;
372 return (memcpy(xmalloc(size), s, size));