Messages in this thread Patch in this message | | | Date | Fri, 13 Aug 1999 01:57:25 +0200 | From | Joerg Pommnitz <> | Subject | Proof of concept/RFC: Reordering of init functions at build time |
| |
Attached please find a patch that implements my proposed way to solve the initialization-oder problem for functions in the .initcall.init section. It introduces an additional step in the build process that reorders init functions according to an external specification. It is has been tested on x86 Linux. It should work on all 32bit architectures. For 64bit architectures, the fiximage program has to be modified to support ELF64. Im interested in comments/suggestions. I hope, that once this has been reviewed, my code can be included into the mainline kernel.
Attached is an example from the last stage of the build of 2.3.13 on my machine. The initdependencies file contains the following line: device_setup: piix4_idle_init kswapd_init
Observe the change of the order in the initialization table. The original order is: piix4_idle_init 0xc0210a90 kswapd_init 0xc021310c bdflush_init 0xc0213424 init_elf_binfmt 0xc02136e4 init_aout_binfmt 0xc0213704 init_script_binfmt 0xc0213724 device_setup 0xc0214e10 parport_init 0xc0217a70 pci_proc_init 0xc021c2c4
The modified order is:
device_setup kswapd_init piix4_idle_init bdflush_init init_elf_binfmt init_aout_binfmt init_script_binfmt parport_init pci_proc_init
As you can see, the functions listed in the dependcy description moved to the top whereas the unlisted functions remained in the original order. The onliest other remark I have to make is, that the binary patched kernel still boots and the system seems stable.
--------------------start final part of build process--------------------------------------- nm vmlinux | grep -v '\(compiled\)\|\(\.o$\)\|\( [aU] \)\|\(\.\.ng$\)\|\(LASH[RL]DI\)' | sort > System.map cat `find /usr/src/linux -name initdependencies -print` | /usr/src/linux/scripts/catdep | tsort | /usr/src/linux/scripts/symaddr -f /usr/src/linux/System.map | /usr/src/linux/scripts/fiximage -d -f /usr/src/linux/vmlinux name is 0, name is 27, .text name is 33, .text.lock name is 44, .rodata name is 52, .kstrtab name is 61, __ex_table name is 72, __ksymtab name is 82, .data name is 88, .data.init_task name is 104, .text.init name is 115, .data.init name is 126, .setup.init name is 138, .initcall.init 0000 -> 0xc0210a90 0001 -> 0xc021310c 0002 -> 0xc0213424 0003 -> 0xc02136e4 0004 -> 0xc0213704 0005 -> 0xc0213724 0006 -> 0xc0214e10 0007 -> 0xc0217a70 0008 -> 0xc021c2c4 0000 -> 0xc0214e10 0001 -> 0xc021310c 0002 -> 0xc0210a90 0003 -> 0xc0213424 0004 -> 0xc02136e4 0005 -> 0xc0213704 0006 -> 0xc0213724 0007 -> 0xc0217a70 0008 -> 0xc021c2c4 1496980 make[1]: Entering directory `/usr/src/linux/arch/i386/boot' make[2]: Entering directory `/usr/src/linux/arch/i386/boot/compressed' tmppiggy=_tmp_$$piggy; \ rm -f $tmppiggy $tmppiggy.gz $tmppiggy.lnk; \ objcopy -O binary -R .note -R .comment -S /usr/src/linux/vmlinux $tmppiggy; \ gzip -f -9 < $tmppiggy > $tmppiggy.gz; \ echo "SECTIONS { .data : { input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) input_data_end = .; }}" > $tmppiggy.lnk; \ ld -m elf_i386 -m elf_i386 -r -o piggy.o -b binary $tmppiggy.gz -b elf32-i386 -T $tmppiggy.lnk; \ rm -f $tmppiggy $tmppiggy.gz $tmppiggy.lnk ld -m elf_i386 -Ttext 0x100000 -e startup_32 -o bvmlinux head.o misc.o piggy.o make[2]: Leaving directory `/usr/src/linux/arch/i386/boot/compressed' objcopy -O binary -R .note -R .comment -S compressed/bvmlinux compressed/bvmlinux.out tools/build -b bbootsect bsetup compressed/bvmlinux.out CURRENT > bzImage Root device is (3, 6) Boot sector 512 bytes. Setup is 3444 bytes. System is 556 kB -------------------------------End of build process---------------------------------
Regards JoergBinary files linux/.System.map.swp and linux.jpo/.System.map.swp differ diff -ruN linux/arch/i386/Makefile linux.jpo/arch/i386/Makefile --- linux/arch/i386/Makefile Tue Jul 13 21:26:46 1999 +++ linux.jpo/arch/i386/Makefile Fri Aug 13 00:22:16 1999 @@ -16,6 +16,10 @@ # Added '-march' and '-mpreferred-stack-boundary' support # +SCRIPTSDIR=$(TOPDIR)/scripts +FIXIMAGE=$(SCRIPTSDIR)/fiximage +CATDEP=$(SCRIPTSDIR)/catdep +SYMADDR=$(SCRIPTSDIR)/symaddr LD=$(CROSS_COMPILE)ld -m elf_i386 CPP=$(CC) -E OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S @@ -77,7 +81,16 @@ MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot -vmlinux: arch/i386/vmlinux.lds +vmlinux: arch/i386/vmlinux.lds $(FIXIMAGE) $(CATDEP) $(SYMADDR) + +$(FIXIMAGE): $(SCRIPTSDIR)/fiximage.c + $(HOSTCC) -o $@ $^ -lelf + +$(CATDEP): $(SCRIPTSDIR)/catdep.c + $(HOSTCC) -o $@ $^ + +$(SYMADDR): $(SCRIPTSDIR)/symaddr.c + $(HOSTCC) -o $@ $^ arch/i386/vmlinux.lds: arch/i386/vmlinux.lds.S FORCE gcc -E -C -P -I$(HPATH) -imacros $(HPATH)/asm-i386/page_offset.h -Ui386 arch/i386/vmlinux.lds.S >arch/i386/vmlinux.lds @@ -88,6 +101,7 @@ @$(MAKEBOOT) zImage bzImage: vmlinux + cat `find $(TOPDIR) -name initdependencies -print` | $(CATDEP) | tsort | $(SYMADDR) -f $(TOPDIR)/System.map | $(FIXIMAGE) -d -f $(TOPDIR)/vmlinux @$(MAKEBOOT) bzImage compressed: zImage diff -ruN linux/initdependencies linux.jpo/initdependencies --- linux/initdependencies Thu Jan 1 01:00:00 1970 +++ linux.jpo/initdependencies Fri Aug 13 00:37:31 1999 @@ -0,0 +1 @@ +device_setup: piix4_idle_init kswapd_init \ No newline at end of file diff -ruN linux/scripts/catdep.c linux.jpo/scripts/catdep.c --- linux/scripts/catdep.c Thu Jan 1 01:00:00 1970 +++ linux.jpo/scripts/catdep.c Thu Aug 12 23:57:44 1999 @@ -0,0 +1,53 @@ +/* + * Author: Joerg Pommnitz (pommnitz@darmstadt.gmd.de) + * + * Copyright (C) 1999 Joerg Pommnitz + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define BUFSIZE (16 * 1024) +const char *WS = "\t \n"; + +int +main (int argc, char *argv[]) +{ + FILE *f = 0; + char buf[BUFSIZE]; + + if (argc == 2) { + if ((f = fopen (argv[1], "rb")) == 0) { + fprintf (stderr, "Invalid file name %s\n", argv[1]); + exit (1); + } + } else { + f = stdin; + } + + while (fgets (buf, BUFSIZE, f)) { + char *start_nodes, *end_nodes; + char *curr; + int i, num_end = 0; + char *end_tokens[BUFSIZE]; + + start_nodes = buf; + end_nodes = strchr (buf, ':'); + + *end_nodes++ = 0; + + for (curr = strtok (end_nodes, WS); curr; curr = strtok (0, WS), num_end++) { + end_tokens[num_end] = curr; + } + + for (curr = strtok (start_nodes, WS); curr; curr = strtok (0, WS)) { + for (i = 0; i < num_end; i++) { + printf ("%s %s\n", curr, end_tokens[i]); + } + } + } + + return 0; +} diff -ruN linux/scripts/fiximage.c linux.jpo/scripts/fiximage.c --- linux/scripts/fiximage.c Thu Jan 1 01:00:00 1970 +++ linux.jpo/scripts/fiximage.c Fri Aug 13 00:25:23 1999 @@ -0,0 +1,208 @@ +/* + * Tool for dependecy fixup in the Linux kernel + * initialization sequence + * + * Author: Joerg Pommnitz (pommnitz@darmstadt.gmd.de) + * + * Copyright (C) 1999 Joerg Pommnitz + * + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> + +#include <elf.h> +#include <libelf/libelf.h> + +#define MAXSYMBOLS (20 * 1024) +#define LINESIZE 256 + +#define NOADDR ((void *)0xffffffff) + +static char *ImageFileName = 0; +static char *SectionName = 0; +static FILE *GoalFile = 0; +static int DebugFlag = 0; + +void Usage (void) +{ + fprintf (stderr, "fiximage [-f file] [-s section] [-g input]\n"); + exit (1); +} + +void +ParseArgv (int argc, char *argv[]) +{ + int c; + + while ((c = getopt (argc, argv, "f:s:g:d")) != -1) { + switch (c) { + case 'd': + DebugFlag++; + break; + case 'f': + ImageFileName = strdup (optarg); + break; + case 's': + SectionName = strdup (optarg); + break; + case 'g': + if ((GoalFile = fopen (optarg, "r")) == 0) { + fprintf (stderr, "Could not open file %s\n", optarg); + } + break; + case '?': + Usage (); + } + } + + if (ImageFileName == 0) { + ImageFileName = "vmlinux"; + } + + if (SectionName == 0) { + SectionName = ".initcall.init"; + } + + if (GoalFile == 0) { + GoalFile = stdin; + } +} + + +int +ElfInit (char *path, Elf **elf, Elf32_Half *ndx) +{ + Elf32_Ehdr *ehdr; + int fd = open (path, O_RDWR); + + if (fd < 0) { + perror ("open"); + return 1; + } + + if (elf_version(EV_CURRENT) == EV_NONE) { + fprintf (stderr, "elf_version: library out of date\n"); + return 1; + } + + if ((*elf = elf_begin(fd, ELF_C_RDWR, 0)) == 0) { + fprintf (stderr, "elf_begin failed\n"); + return 1; + } + + if ((ehdr = elf32_getehdr(*elf)) == 0) { + fprintf (stderr, "elf32_getehdr failed\n"); + return 1; + } + + *ndx = ehdr->e_shstrndx; + + return 0; +} + +Elf_Scn * +GetSectionByName (Elf *elf, Elf32_Half str_scn, char *name) +{ + Elf_Scn *scn; + + for (scn = elf_getscn(elf, 0); scn; scn = elf_nextscn(elf, scn)) { + Elf32_Shdr *hdr = elf32_getshdr(scn); + char *current_name = elf_strptr (elf, str_scn, hdr->sh_name); + + if (DebugFlag) + printf ("name is %d, %s\n", hdr->sh_name, current_name); + + if (strcmp (name, current_name) == 0) + return scn; + } + + return 0; +} + +int +main (int argc, char *argv[]) +{ + Elf *elf; + Elf32_Half str_scn; + Elf_Scn *scn; + Elf_Data *data; + void **functs; + void **reordered; + void *DestOrder[MAXSYMBOLS]; + char buf[LINESIZE]; + int num_entries, i, j; + + ParseArgv (argc, argv); + + for (num_entries = 0; fgets (buf, LINESIZE, GoalFile); num_entries++) { + sscanf (buf, "%p\n", DestOrder + num_entries); + } + + if (ElfInit (ImageFileName, &elf, &str_scn) != 0) { + return -1; + } + + scn = GetSectionByName (elf, str_scn, SectionName); + + if (scn == 0) { + fprintf (stderr, "could not find ELF section %s\n", SectionName); + exit (1); + } + + data = elf_getdata(scn, 0); + + reordered = malloc (data->d_size); + + /* special hack for the .ctors section: the real constructor + table seems to be enclosed in 0x00000000 and 0xffffffff */ + + if (strcmp (SectionName, ".ctors") == 0) { + reordered[0] = (void *)(0xffffffff); + j = 1; + } else { + j = 0; + } + + if (DebugFlag) { + for (functs = data->d_buf, i = 0; &functs[i] < (void **)(data->d_buf + data->d_size); i++) { + fprintf (stderr, "%04d -> %p\n", i, functs[i]); + } + } + + for (i = 0; i < num_entries; i++) { + for (functs = data->d_buf; functs < (void **)(data->d_buf + data->d_size); functs++) { + if (DestOrder [i] == *functs) { + reordered[j++] = *functs; + *functs = NOADDR; + break; + } + } + } + + for (functs = data->d_buf; functs < (void **)(data->d_buf + data->d_size); functs++) { + if (*functs != NOADDR) { + reordered[j++] = *functs; + } + } + + memcpy (data->d_buf, reordered, data->d_size); + + if (DebugFlag) { + for (functs = data->d_buf, i = 0; &functs[i] < (void **)(data->d_buf + data->d_size); i++) { + fprintf (stderr, "%04d -> %p\n", i, functs[i]); + } + } + + if (DebugFlag) + printf ("%d\n", elf_update(elf, ELF_C_WRITE)); + + elf_end(elf); + + return 0; +} diff -ruN linux/scripts/symaddr.c linux.jpo/scripts/symaddr.c --- linux/scripts/symaddr.c Thu Jan 1 01:00:00 1970 +++ linux.jpo/scripts/symaddr.c Thu Aug 12 23:57:50 1999 @@ -0,0 +1,107 @@ +/* + * Author: Joerg Pommnitz (pommnitz@darmstadt.gmd.de) + * + * Copyright (C) 1999 Joerg Pommnitz + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#define BUFSIZE (16 * 1024) +#define LINESIZE (16 * 1024) + +struct mapping { + void *sym_addr; + char sym_name[128]; +} mapping_buf[BUFSIZE]; + +static FILE *SymbolFile = 0; +static FILE *QueryFile = 0; + +int +CompareFunc (const void *e1, const void *e2) +{ + const struct mapping *p1 = e1, *p2 = e2; + + return strcmp (p1->sym_name, p2->sym_name); +} + +void +Usage (void) +{ + fprintf (stderr, "Usage: symaddr -f symbol_file\n"); + exit (1); +} + +void +ParseArgv (int argc, char *argv[]) +{ + int c; + + while ((c = getopt (argc, argv, "f:")) != -1) { + switch (c) { + case 'f': + if ((SymbolFile = fopen (optarg, "rb")) == 0) { + fprintf (stderr, "Could not open symbol file %s!\n", optarg); + exit (1); + } + break; + case 'q': + if ((QueryFile = fopen (optarg, "rb")) == 0) { + fprintf (stderr, "Could not open query file %s!\n", optarg); + exit (1); + } + break; + case '?': + Usage (); + } + } + + if (SymbolFile == 0) { + Usage (); + } + + if (QueryFile == 0) { + QueryFile = stdin; + } +} + +int +main (int argc, char *argv[]) +{ + char buf[LINESIZE] = {'0','x',}; + int num_mappings, i; + + ParseArgv (argc, argv); + + for (num_mappings = 0; fgets (buf + 2, LINESIZE, SymbolFile); num_mappings++) { + char dummy; + sscanf (buf, "%p %c %s\n", + &mapping_buf[num_mappings].sym_addr, + &dummy, mapping_buf[num_mappings].sym_name); + } + + qsort (mapping_buf, num_mappings, sizeof (mapping_buf[0]), CompareFunc); + + while (fgets (buf, LINESIZE, QueryFile)) { + struct mapping key; + struct mapping *res; + char *p; + + if (p = strrchr (buf, '\n')) { + *p = 0; + } + + strcpy (key.sym_name, buf); + + if ((res = bsearch (&key, mapping_buf, num_mappings, + sizeof (mapping_buf[0]), CompareFunc)) != 0) { + printf ("%p\n", res->sym_addr); + } + } + + return 0; +}
| |