summaryrefslogtreecommitdiffstats
path: root/usr.bin/genassym
diff options
context:
space:
mode:
authormarcel <marcel@FreeBSD.org>1999-12-23 11:07:45 +0000
committermarcel <marcel@FreeBSD.org>1999-12-23 11:07:45 +0000
commitea6b5e2384139beabfec36a6ea36db9bd058e542 (patch)
tree330b4ae5880c79982ff524d833b05d33cda72c92 /usr.bin/genassym
parentf39fe09d784b3128b128c1bdbe12e72de1e2df34 (diff)
downloadFreeBSD-src-ea6b5e2384139beabfec36a6ea36db9bd058e542.zip
FreeBSD-src-ea6b5e2384139beabfec36a6ea36db9bd058e542.tar.gz
New command for creating assembler symbols from C.
Diffstat (limited to 'usr.bin/genassym')
-rw-r--r--usr.bin/genassym/Makefile9
-rw-r--r--usr.bin/genassym/genassym.868
-rw-r--r--usr.bin/genassym/genassym.c271
3 files changed, 348 insertions, 0 deletions
diff --git a/usr.bin/genassym/Makefile b/usr.bin/genassym/Makefile
new file mode 100644
index 0000000..c85dc9b
--- /dev/null
+++ b/usr.bin/genassym/Makefile
@@ -0,0 +1,9 @@
+# $FreeBSD$
+
+TARGET_ARCH?= ${MACHINE_ARCH}
+
+PROG= genassym
+MAN8= genassym.8
+CFLAGS+= -Wall -Darch_${TARGET_ARCH}
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/genassym/genassym.8 b/usr.bin/genassym/genassym.8
new file mode 100644
index 0000000..8ee2581
--- /dev/null
+++ b/usr.bin/genassym/genassym.8
@@ -0,0 +1,68 @@
+.\"
+.\" $FreeBSD$
+.\"
+.Dd December 20, 1999
+.Dt GENASSYM 8
+.Os
+.Sh NAME
+.Nm genassym
+.Nd generate assembler symbols from C
+.Sh SYNOPSIS
+.Nm genassym
+.Op Fl o Ar outfile
+.Ar objfile
+.Sh DESCRIPTION
+The
+.Nm
+command is a special-purpose program to generate assembler
+symbols from C code and is used to interface the low-level
+assembly code with the C code. This, for example, is used
+to build a FreeBSD kernel or module.
+Its
+.Ar objfile
+argument is the name of an ELF object file that holds the
+symbol definitions. These definitions are extracted from
+the object file and written to standard output or to the
+file specified with
+.Ar outfile ,
+suitable for inclusion in assembler source files.
+.Pp
+The
+.Nm
+command only extracts symbols from the object file if they
+are prefixed by
+.Nm assym_
+and are global data types, whose value is the value given
+to the symbol. The following C declaration
+.Bd -literal -offset indent -compact
+int assym_MY_SYMBOL = 3;
+.Ed
+is used to create the following assembler symbol.
+.Bd -literal -offset indent -compact
+#define MY_SYMBOL 0x3
+.Ed
+Note that the size of the symbol is extracted from the
+object file, which means that the symbol may have any type
+that is wide enough to hold the value.
+.Sh SEE ALSO
+.Xr config 8
+.Xr gensetdefs 8
+.Sh AUTHORS
+The
+.Nm
+command was written by
+.An Marcel Moolenaar Aq marcel@FreeBSD.org
+and was based on the
+.Dv gensetdefs
+command.
+.Sh BUGS
+Not all linkers store the size of the symbol in the ELF
+object file. The GNU linker for Alpha has this bug for
+example (binutils 2.9.1). In those cases the size of the
+symbol is assumed to be equal to the word size of the ELF
+object file. For Alpha this is 64 bits and for i386 this
+is 32 bits.
+.Sh HISTORY
+The
+.Nm
+command first appeared in FreeBSD 4.0.
diff --git a/usr.bin/genassym/genassym.c b/usr.bin/genassym/genassym.c
new file mode 100644
index 0000000..52a1877
--- /dev/null
+++ b/usr.bin/genassym/genassym.c
@@ -0,0 +1,271 @@
+/*-
+ * Copyright (c) 1999 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#if defined(arch_i386)
+#include <sys/elf32.h>
+#define __ELF_WORD_SIZE 32
+#elif defined(arch_alpha)
+#include <sys/elf64.h>
+#define __ELF_WORD_SIZE 64
+#else
+#error unknown or missing architecture
+#endif
+#include <sys/elf_generic.h>
+
+#include <err.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+const char s_data[] = ".data";
+const char s_strtab[] = ".strtab";
+const char s_symtab[] = ".symtab";
+const char assym[] = "assym_";
+
+int fd;
+char *objfile;
+Elf_Ehdr ehdr;
+Elf_Shdr *shdr;
+char *shstr;
+
+int
+my_byte_order(void)
+{
+ static unsigned short s = 0xbbaa;
+ int byte0;
+
+ byte0 = *(unsigned char *)&s;
+ if (byte0 == 0xaa)
+ return (ELFDATA2LSB);
+ else if (byte0 == 0xbb)
+ return (ELFDATA2MSB);
+ return (ELFDATANONE);
+}
+
+void *
+read_section(int index)
+{
+ void *buf;
+ size_t size;
+ ssize_t bytes;
+
+ size = shdr[index].sh_size;
+ buf = malloc(size);
+ if (buf == NULL)
+ return (NULL);
+ if (lseek(fd, shdr[index].sh_offset, SEEK_SET) == -1)
+ return (NULL);
+ bytes = read(fd, buf, size);
+ if (bytes == -1)
+ return (NULL);
+ if (bytes != size)
+ warnx("%s: section %d partially read", objfile, index);
+ return (buf);
+}
+
+int section_index(const char *section)
+{
+ int i;
+
+ for (i = 1; i < ehdr.e_shnum; i++)
+ if (!strcmp(section, shstr + shdr[i].sh_name))
+ return (i);
+ return (-1);
+}
+
+char *
+filter(char *name)
+{
+ char *dot;
+
+ name += sizeof(assym) - 1;
+ dot = strchr(name, '.');
+ if (dot != NULL)
+ *dot = '\0';
+ return (name);
+}
+
+void usage(void)
+{
+ fprintf(stderr, "usage: genassym [-o outfile] objfile\n");
+ exit(1);
+ /* NOT REACHED */
+}
+
+int
+main(int argc, char *argv[])
+{
+ Elf_Sym *sym;
+ char *data, *name, *symbols;
+ char *outfile;
+ void *valp;
+ size_t size;
+ ssize_t bytes;
+ int ch, i, numsym, warn_ld_bug;
+ int si_data, si_strtab, si_symtab;
+ u_int64_t value;
+
+ outfile = NULL;
+ warn_ld_bug = 1;
+
+ while ((ch = getopt(argc, argv, "o:")) != -1) {
+ switch (ch) {
+ case 'o':
+ outfile = optarg;
+ break;
+ default:
+ usage();
+ /* NOT REACHED */
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 0) {
+ usage();
+ /* NOT REACHED */
+ }
+ if (argc > 1)
+ warnx("ignoring trailing arguments");
+
+ objfile = argv[0];
+ fd = open(objfile, O_RDONLY);
+ if (fd == -1)
+ err(1, "%s", objfile);
+
+ bytes = read(fd, &ehdr, sizeof(ehdr));
+ if (bytes == -1)
+ err(1, "%s", objfile);
+ if (bytes != sizeof(ehdr) ||
+ ehdr.e_ident[EI_MAG0] != ELFMAG0 ||
+ ehdr.e_ident[EI_MAG1] != ELFMAG1 ||
+ ehdr.e_ident[EI_MAG2] != ELFMAG2 ||
+ ehdr.e_ident[EI_MAG3] != ELFMAG3)
+ errx(1, "%s: not an ELF file", objfile);
+ if (ehdr.e_ident[EI_VERSION] != EV_CURRENT)
+ errx(1, "%s: unsupported ELF version", objfile);
+ if (ehdr.e_ident[EI_DATA] != my_byte_order())
+ errx(1, "%s: unsupported byte order", objfile);
+ if (ehdr.e_shoff == 0)
+ errx(1, "%s: no section table", objfile);
+ if (ehdr.e_shstrndx == SHN_UNDEF)
+ errx(1, "%s: no section name string table", objfile);
+
+ size = sizeof(*shdr) * ehdr.e_shnum;
+ shdr = malloc(size);
+ if (shdr == NULL)
+ err(1, "malloc");
+ if (lseek(fd, ehdr.e_shoff, SEEK_SET) == -1)
+ err(1, "%s", objfile);
+ bytes = read(fd, shdr, size);
+ if (bytes == -1)
+ err(1, "%s", objfile);
+ if (bytes != size)
+ errx(1, "%s: truncated section table", objfile);
+
+ shstr = read_section(ehdr.e_shstrndx);
+ if (shstr == NULL)
+ err(1, "%s[%d]", objfile, ehdr.e_shstrndx);
+
+ si_data = section_index(s_data);
+ if (si_data == -1)
+ errx(1, "%s: section %s not present", objfile, s_data);
+ data = read_section(si_data);
+ if (data == NULL)
+ err(1, "%s[%d]", objfile, si_data);
+
+ si_strtab = section_index(s_strtab);
+ if (si_strtab == -1)
+ errx(1, "%s: section %s not present", objfile, s_strtab);
+ symbols = read_section(si_strtab);
+ if (symbols == NULL)
+ err(1, "%s[%d]", objfile, si_strtab);
+
+ si_symtab = section_index(s_symtab);
+ if (si_symtab == -1)
+ errx(1, "%s: section %s not present", objfile, s_symtab);
+ sym = read_section(si_symtab);
+ if (sym == NULL)
+ err(1, "%s[%d]", objfile, si_symtab);
+
+ numsym = shdr[si_symtab].sh_size / sizeof(*sym);
+
+ if (outfile != NULL)
+ freopen(outfile, "w", stdout);
+
+ for (i = 0; i < numsym; i++) {
+ name = symbols + sym[i].st_name;
+ if (sym[i].st_shndx == si_data &&
+ !strncmp(name, assym, sizeof(assym) - 1)) {
+ valp = (void*)(data + sym[i].st_value);
+ /*
+ * XXX - ld(1) on Alpha doesn't store the size of
+ * the symbol in the object file. The following
+ * fix handles this case quite genericly. It
+ * assumes that the symbols have the same size as
+ * a word on that architecture, determined by the
+ * word size in the ELF object file.
+ */
+ if (sym[i].st_size == 0) {
+ sym[i].st_size = __ELF_WORD_SIZE >> 3;
+ if (warn_ld_bug) {
+ warnx("%s: symbol sizes not properly"
+ " set", objfile);
+ warn_ld_bug = 0;
+ }
+ }
+ switch (sym[i].st_size) {
+ case 1:
+ value = *(u_int8_t*)valp;
+ break;
+ case 2:
+ value = *(u_int16_t*)valp;
+ break;
+ case 4:
+ value = *(u_int32_t*)valp;
+ break;
+ case 8:
+ value = *(u_int64_t*)valp;
+ break;
+ default:
+ warnx("unsupported size (%lld) for symbol %s",
+ (long long)sym[i].st_size, filter(name));
+ continue;
+ }
+ fprintf(stdout, "#define\t%s 0x%llx\n", filter(name),
+ (long long)value);
+ }
+ }
+
+ return (0);
+}
OpenPOWER on IntegriCloud