diff options
31 files changed, 3801 insertions, 243 deletions
@@ -22,6 +22,7 @@ *.sec *.sys *_bin.c +*.dyn *~ \#* .\#* @@ -39,3 +40,6 @@ /utils/mkdiskimage /version.h /version.mk +/.cproject +/.project +/exttest diff --git a/com32/Makefile b/com32/Makefile index e9608a58..8189df3d 100644 --- a/com32/Makefile +++ b/com32/Makefile @@ -1,3 +1,4 @@ -SUBDIRS = tools lib gpllib libutil modules mboot menu samples rosh cmenu hdt +SUBDIRS = tools lib gpllib libutil modules mboot menu samples elflink elflink/modules rosh cmenu hdt + all tidy dist clean spotless install: set -e; for d in $(SUBDIRS); do $(MAKE) -C $$d $@; done diff --git a/com32/elflink/Makefile b/com32/elflink/Makefile new file mode 100644 index 00000000..011e18d3 --- /dev/null +++ b/com32/elflink/Makefile @@ -0,0 +1,43 @@ +## ----------------------------------------------------------------------- +## +## Copyright 2001-2008 H. Peter Anvin - All Rights Reserved +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation, Inc., 53 Temple Place Ste 330, +## Boston MA 02111-1307, USA; either version 2 of the License, or +## (at your option) any later version; incorporated herein by reference. +## +## ----------------------------------------------------------------------- + +topdir = ../.. +include ../MCONFIG + +MODULES = test_memalign.c32 test_com32.c32 + +TESTFILES = + +all: $(MODULES) $(TESTFILES) + +test_memalign.elf : test_memalign.o $(LIBS) $(C_LIBS) + $(LD) $(LDFLAGS) -o $@ $^ + +test_com32.elf: CFLAGS += -DELF_DEBUG +test_com32.elf: test_com32.o ../libutil/libutil_com.a ../lib/libcom32min.a $(LIBGCC) + $(LD) -n $(LDFLAGS) -o $@ test_com32.o ../libutil/libutil_com.a $(LIBGCC) --whole-archive ../lib/libcom32min.a -Map test_com32.map + $(OBJCOPY) --extract-symbol $@ _root_.dyn + +tidy dist: + rm -f *.o *.lo *.a *.lst *.elf .*.d *.map + +clean: tidy + rm -f *.lss *.c32 *.lnx *.com *.dyn + +spotless: clean + rm -f *~ \#* + +install: all + mkdir -m 755 -p $(INSTALLROOT)$(AUXDIR) + install -m 644 $(MODULES) $(INSTALLROOT)$(AUXDIR) + +-include .*.d diff --git a/com32/elflink/modules/MCONFIG b/com32/elflink/modules/MCONFIG new file mode 100644 index 00000000..18845877 --- /dev/null +++ b/com32/elflink/modules/MCONFIG @@ -0,0 +1,62 @@ +## -*- makefile -*- ------------------------------------------------------- +## +## Copyright 2008 H. Peter Anvin - All Rights Reserved +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +## Boston MA 02110-1301, USA; either version 2 of the License, or +## (at your option) any later version; incorporated herein by reference. +## +## ----------------------------------------------------------------------- + +## +## COM32 common configurables +## + +include $(topdir)/MCONFIG + +GCCOPT := $(call gcc_ok,-std=gnu99,) \ + $(call gcc_ok,-m32,) \ + $(call gcc_ok,-fno-stack-protector,) \ + -mregparm=3 -DREGPARM=3 -march=i386 -Os + +com32 = $(topdir)/com32 + +CFLAGS = $(GCCOPT) -W -Wall -march=i386 \ + -fomit-frame-pointer -D__COM32__ -DDYNAMIC_MODULE \ + -nostdinc -iwithprefix include \ + -I$(com32)/libutil/include -I$(com32)/include +SFLAGS = $(GCCOPT) -D__COM32__ -march=i386 +LDFLAGS = -m elf_i386 -shared -T $(com32)/lib/elf32.ld +LIBGCC := $(shell $(CC) $(GCCOPT) --print-libgcc) + +LNXCFLAGS = -I$(com32)/libutil/include -W -Wall -O -g -D_GNU_SOURCE +LNXSFLAGS = -g +LNXLDFLAGS = -g + +.SUFFIXES: .lss .c .o .dyn + +.PRECIOUS: %.o +%.o: %.S + $(CC) $(SFLAGS) -c -o $@ $< + +.PRECIOUS: %.o +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + +.PRECIOUS: %.dyn +%.dyn: %.o $(LIBS) + $(LD) $(LDFLAGS) -o $@ $^ + +.PRECIOUS: %.lo +%.lo: %.S + $(CC) $(LNXSFLAGS) -c -o $@ $< + +.PRECIOUS: %.lo +%.lo: %.c + $(CC) $(LNXCFLAGS) -c -o $@ $< + +.PRECIOUS: %.lnx +%.lnx: %.lo $(LNXLIBS) + $(CC) $(LNXLDFLAGS) -o $@ $^ diff --git a/com32/elflink/modules/Makefile b/com32/elflink/modules/Makefile new file mode 100644 index 00000000..6bf17e3c --- /dev/null +++ b/com32/elflink/modules/Makefile @@ -0,0 +1,41 @@ +## ----------------------------------------------------------------------- +## +## Copyright 2001-2008 H. Peter Anvin - All Rights Reserved +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation, Inc., 53 Temple Place Ste 330, +## Boston MA 02111-1307, USA; either version 2 of the License, or +## (at your option) any later version; incorporated herein by reference. +## +## ----------------------------------------------------------------------- + +topdir = ../../.. +include MCONFIG + +MODULES = hello.dyn sort.dyn + +TESTFILES = + +all: $(MODULES) $(TESTFILES) + +hello.dyn : hello.o + $(LD) $(LDFLAGS) -o $@ $^ + +sort.dyn : sort.o + $(LD) $(LDFLAGS) -o $@ $^ + +tidy dist: + rm -f *.o *.lo *.a *.lst .*.d + +clean: tidy + rm -f *.lss *.lnx *.com *.dyn + +spotless: clean + rm -f *~ \#* + +install: all + mkdir -m 755 -p $(INSTALLROOT)$(AUXDIR) + install -m 644 $(MODULES) $(INSTALLROOT)$(AUXDIR) + +-include .*.d diff --git a/com32/elflink/modules/README b/com32/elflink/modules/README new file mode 100644 index 00000000..090313a7 --- /dev/null +++ b/com32/elflink/modules/README @@ -0,0 +1 @@ +This folder contains dynamically loadable ELF modules for SYSLINUX.
\ No newline at end of file diff --git a/com32/elflink/modules/hello.c b/com32/elflink/modules/hello.c new file mode 100644 index 00000000..dc87004d --- /dev/null +++ b/com32/elflink/modules/hello.c @@ -0,0 +1,51 @@ +/* + * hello.c - A simple ELF module that sorts a couple of numbers + * + * Created on: Aug 11, 2008 + * Author: Stefan Bucur <stefanb@zytor.com> + */ + +#include <stdio.h> +#include <stdlib.h> +#include <sys/module.h> + +#include "sort.h" + + +#define NUM_COUNT 10 +#define MAX_NUM 100 + + +static int hello_main(int argc, char **argv) { + int *nums = NULL; + int i; + + printf("Hello, world, from 0x%08X!\n", (unsigned int)&hello_main); + + nums = malloc(NUM_COUNT*sizeof(int)); + + for (i = 0; i < NUM_COUNT; i++) { + nums[i] = rand() % MAX_NUM; + } + + printf("Numbers before sort: "); + for (i = 0; i < NUM_COUNT; i++) { + printf("%d ", nums[i]); + } + printf("\n"); + + quick_sort(nums, NUM_COUNT); + + printf("Numbers after sort: "); + for (i = 0; i < NUM_COUNT; i++) { + printf("%d ", nums[i]); + } + printf("\n"); + + free(nums); + + return 0; +} + + +MODULE_MAIN(hello_main); diff --git a/com32/elflink/modules/sort.c b/com32/elflink/modules/sort.c new file mode 100644 index 00000000..bec0ef2a --- /dev/null +++ b/com32/elflink/modules/sort.c @@ -0,0 +1,75 @@ +/* + * sort.c - Sample ELF module providing a quick sort function + * + * Created on: Aug 11, 2008 + * Author: Stefan Bucur <stefanb@zytor.com> + */ + +#include <stdlib.h> +#include <sys/module.h> + +/** + * sort_init - Module entry point. + */ +static int sort_init() { + return 0; // Nothing to do; return success +} + + +static inline void swap(int *x, int *y) { + int tmp; + tmp = *x; + *x = *y; + *y = tmp; +} + +static inline int randint(int l, int u) { + return l + (rand() % (u-l+1)); +} + +/** + * quick_sort_range - A small and efficient version of quicksort. + * @nums: The numbers to sort + * @l: The lower index in the vector (inclusive) + * @u: The upper index in the vector (inclusive) + * + * The implementation is taken from "Beautiful Code", by O'Reilly, the + * book students received from Google as a gift for their acceptance + * in the GSoC 2008 program. The code belongs to Jon Bentley, who + * wrote the third chapter of the book. Since ELF modules were written + * as part of this program, the author of the module considered + * the book had to be put at some use. :) + */ +static void quick_sort_range(int *nums, int l, int u) { + int i, m; + if (l >= u) return; + + swap(&nums[l], &nums[randint(l, u)]); + + m = l; + for (i = l+1; i <= u; i++) { + if (nums[i] < nums[l]) + swap(&nums[++m], &nums[i]); + } + + swap(&nums[l], &nums[m]); + + quick_sort_range(nums, l, m-1); + quick_sort_range(nums, m+1, u); +} + + +void quick_sort(int *nums, int count) { + quick_sort_range(nums, 0, count-1); +} + +/** + * sort_exit - Module exit point. + */ +static void sort_exit() { + // Nothing to do +} + +// Define entry and exit points. +MODULE_INIT(sort_init); +MODULE_EXIT(sort_exit); diff --git a/com32/elflink/modules/sort.h b/com32/elflink/modules/sort.h new file mode 100644 index 00000000..35b8f5a6 --- /dev/null +++ b/com32/elflink/modules/sort.h @@ -0,0 +1,19 @@ +/* + * sort.h - Quick sort module API definitions + * + * Created on: Aug 11, 2008 + * Author: Stefan Bucur <stefanb@zytor.com> + */ + +#ifndef SORT_H_ +#define SORT_H_ + +/** + * quick_sort - In place sort of an array of numbers. + * @nums: Pointer to the array + * @count: The number count in the array + */ +extern void quick_sort(int *nums, int count); + + +#endif /* SORT_H_ */ diff --git a/com32/elflink/test_com32.c b/com32/elflink/test_com32.c new file mode 100644 index 00000000..115bba87 --- /dev/null +++ b/com32/elflink/test_com32.c @@ -0,0 +1,203 @@ +#include <stdio.h> +#include <stdlib.h> +#include <console.h> +#include <string.h> + +#include <sys/module.h> +#include <sys/exec.h> + +#define INFO_PRINT(fmt, args...) printf("[COM32] " fmt, ##args) + +#define MAX_COMMAND_SIZE 80 // Maximum size of the cmd line +#define COMMAND_DELIM " \t\n" // Whitespace delimiters +#define MAX_COMMAND_ARGS (MAX_COMMAND_SIZE/2) // Maximum argument count for + // program execution + + + +/** + * print_help - Display usage instructions on the screen. + */ +static void print_help() { + printf("List of available commands:\n"); + printf("exit - exits the program\n"); + printf("help - shows this message\n"); + printf("load <library>... - loads the libraries into the environment\n"); + printf("spawn <executable> <args> - launches an executable module\n"); + printf("unload <library>... - unloads the libraries from the environment\n"); + printf("list - prints the currently loaded modules\n"); +} + +/** + * print_prompt - Display the command prompt. + */ +static void print_prompt() { + printf("\nelflink> "); +} + +/** + * read_command - Read a new command from the standard input. + * @cmd: the buffer to store the command + * @size: the maximum size of the string that can be stored in the buffer + * + * If the command is larger than the specified size, it is truncated. + */ +static void read_command(char *cmd, int size) { + char *nl = NULL; + fgets(cmd, size, stdin); + + // Strip the newline + nl = strchr(cmd, '\n'); + + if (nl != NULL) + *nl = '\0'; +} + +/** + * process_spawn - Handles the execution of a 'spawn' command. + * + * The command line is in the internal buffer of strtok. + */ +static void process_spawn() { + // Compose the command line + char **cmd_line = malloc((MAX_COMMAND_ARGS+1)*sizeof(char*)); + int argc = 0, result; + char *crt_arg; + + do { + crt_arg = strtok(NULL, COMMAND_DELIM); + if (crt_arg != NULL && strlen(crt_arg) > 0) { + cmd_line[argc] = crt_arg; + argc++; + } else { + break; + } + } while (argc < MAX_COMMAND_ARGS); + + cmd_line[argc] = NULL; + + if (cmd_line[0] == NULL) { + printf("You must specify an executable module.\n"); + } else { + result = spawnv(cmd_line[0], cmd_line); + + printf("Spawn returned %d\n", result); + } + + free(cmd_line); +} + +/** + * process_library - Handles the execution of the 'load' and 'unload' commands. + * @load: contains 1 if the libraries are to be loaded, 0 for unloading. + * + * The command line is in the internal buffer of strtok. + */ +static void process_library(int load) { + char *crt_lib; + int result; + + while ((crt_lib = strtok(NULL, COMMAND_DELIM)) != NULL) { + if (strlen(crt_lib) > 0) { + if (load) + result = load_library(crt_lib); + else + result = unload_library(crt_lib); + + if (result == 0) { + printf("Library '%s' %sloaded successfully.\n", crt_lib, + load ? "" : "un"); + } else { + printf("Could not %sload library '%s': error %d\n", + load ? "" : "un", crt_lib, result); + } + } + } +} + +/** + * process_list - Handles the execution of the 'list' command. + * + */ +static void process_list() { + struct elf_module *module; + struct module_dep *crt_dep; + + for_each_module(module) { + printf("%s (%dK, %s, %s) : ", module->name, module->module_size >> 10, + module->shallow ? "shallow" : "regular", + module->main_func == NULL ? "library" : "program"); + + list_for_each_entry(crt_dep, &module->required, list) { + printf("%s ", crt_dep->module->name); + } + + printf("\n"); + } +} + +/** + * process_command - Recognizes the requested command and executes it. + * @cmd: the command to be executed. + * + * Returns 1 if the command was 'exit', 0 otherwise. + */ +static int process_command(char *cmd) { + char *cmd_name; + + cmd_name = strtok(cmd, COMMAND_DELIM); + + if (strcmp(cmd_name, "exit") == 0) { + printf("Goodbye!\n"); + return 1; + } else if (strcmp(cmd_name, "help") == 0) { + print_help(); + } else if (strcmp(cmd_name, "load") == 0) { + process_library(1); + } else if (strcmp(cmd_name, "spawn") == 0) { + process_spawn(); + } else if (strcmp(cmd_name, "unload") == 0) { + process_library(0); + } else if (strcmp(cmd_name, "list") == 0) { + process_list(); + } else { + printf("Unknown command. Type 'help' for a list of valid commands.\n"); + } + + return 0; +} + + +/** + * The entry point of 'test_com32' COM module. + */ +int main(int argc, char **argv) { + int done = 0; + int res; + char command[MAX_COMMAND_SIZE] = {0}; + + // Open a standard r/w console + openconsole(&dev_stdcon_r, &dev_stdcon_w); + + res = exec_init(); + if (res != 0) { + printf("Failed to initialize the execution environment.\n"); + return res; + } else { + printf("Execution environment initialized successfully.\n"); + } + + + printf("\nFor a list of available commands, type 'help'.\n"); + + do { + print_prompt(); + read_command(command, MAX_COMMAND_SIZE); + done = process_command(command); + + } while (!done); + + exec_term(); + + return 0; +} diff --git a/com32/elflink/test_memalign.c b/com32/elflink/test_memalign.c new file mode 100644 index 00000000..ea2b0165 --- /dev/null +++ b/com32/elflink/test_memalign.c @@ -0,0 +1,47 @@ +#include <stdio.h> +#include <stdlib.h> +#include <console.h> +#include <errno.h> + +void perform_allocation(int align) { + int res = 0; + int size = 100; + void *ptr; + + printf("Allocation aligned at 0x%05X bytes: ", align); + res = posix_memalign(&ptr, align, size); + + switch (res) { + case 0: + printf("address 0x%08X\n", ptr); + break; + case EINVAL: + printf("EINVAL\n"); + break; + case ENOMEM: + printf("ENOMEM\n"); + break; + } +} + +int main(int argc, char **argv) { + int align = 0x10000; + + // Open a standard r/w console + openconsole(&dev_stdcon_r, &dev_stdcon_w); + + while (align >= sizeof(void*)) { + perform_allocation(align); + align /= 2; + } + + printf("\n"); + + while (align <= 0x10000) { + perform_allocation(align); + align *= 2; + } + + return 0; +} + diff --git a/com32/include/klibc/compiler.h b/com32/include/klibc/compiler.h index 5ac21185..b5919d67 100644 --- a/com32/include/klibc/compiler.h +++ b/com32/include/klibc/compiler.h @@ -108,6 +108,9 @@ # define __unusedfunc #endif +/* Used symbol */ +#define __used __attribute__((used)) + /* Constructors and destructors */ #define __constructor __attribute__((constructor)) #define __destructor __attribute__((destructor)) @@ -126,4 +129,7 @@ #define __common __attribute__((common)) #define __nocommon __attribute__((nocommon)) +/* Weak symbols */ +#define __weak __attribute__((weak)) + #endif diff --git a/com32/include/linux/list.h b/com32/include/linux/list.h new file mode 100644 index 00000000..3b92e254 --- /dev/null +++ b/com32/include/linux/list.h @@ -0,0 +1,463 @@ +// This list structure implementation is adapted from the list implementation +// on the Linux kernel. + +// Original source: +// http://git.kernel.org/?p=linux/kernel/git/stable/linux-2.6.25.y.git;a=blob_plain;f=include/linux/list.h;hb=HEAD + +#ifndef _LINUX_LIST_H +#define _LINUX_LIST_H + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +#include <stdlib.h> +#include <stddef.h> + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +static inline void INIT_LIST_HEAD(struct list_head *list) +{ + list->next = list; + list->prev = list; +} + +/** + * container_of - cast a member of a structure out to the containing structure + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + + + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head * prev, struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty() on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = NULL; + entry->prev = NULL; +} + +/** + * list_replace - replace old entry by new one + * @old : the element to be replaced + * @new : the new element to insert + * + * If @old was empty, it will be overwritten. + */ +static inline void list_replace(struct list_head *old, + struct list_head *new) +{ + new->next = old->next; + new->next->prev = new; + new->prev = old->prev; + new->prev->next = new; +} + +static inline void list_replace_init(struct list_head *old, + struct list_head *new) +{ + list_replace(old, new); + INIT_LIST_HEAD(old); +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void list_del_init(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + INIT_LIST_HEAD(entry); +} + +/** + * list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +static inline void list_move(struct list_head *list, struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add(list, head); +} + +/** + * list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +static inline void list_move_tail(struct list_head *list, + struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add_tail(list, head); +} + +/** + * list_is_last - tests whether @list is the last entry in list @head + * @list: the entry to test + * @head: the head of the list + */ +static inline int list_is_last(const struct list_head *list, + const struct list_head *head) +{ + return list->next == head; +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(const struct list_head *head) +{ + return head->next == head; +} + +/** + * list_empty_careful - tests whether a list is empty and not being modified + * @head: the list to test + * + * Description: + * tests whether a list is empty _and_ checks that no other CPU might be + * in the process of modifying either member (next or prev) + * + * NOTE: using list_empty_careful() without synchronization + * can only be safe if the only activity that can happen + * to the list entry is list_del_init(). Eg. it cannot be used + * if another CPU could re-list_add() it. + */ +static inline int list_empty_careful(const struct list_head *head) +{ + struct list_head *next = head->next; + return (next == head) && (next == head->prev); +} + +static inline void __list_splice(struct list_head *list, + struct list_head *head) +{ + struct list_head *first = list->next; + struct list_head *last = list->prev; + struct list_head *at = head->next; + + first->prev = head; + head->next = first; + + last->next = at; + at->prev = last; +} + +/** + * list_splice - join two lists + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice(struct list_head *list, struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head); +} + +/** + * list_splice_init - join two lists and reinitialise the emptied list. + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * The list at @list is reinitialised + */ +static inline void list_splice_init(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head); + INIT_LIST_HEAD(list); + } +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +/** + * list_first_entry - get the first element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + * + * Note, that list is expected to be not empty. + */ +#define list_first_entry(ptr, type, member) \ + list_entry((ptr)->next, type, member) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); \ + pos = pos->next) + +/** + * __list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + * + * This variant differs from list_for_each() in that it's the + * simplest possible list iteration code, no prefetching is done. + * Use this for code that knows the list to be very short (empty + * or 1 entry) most of the time. + */ +#define __list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_prev - iterate over a list backwards + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev; pos != (head); \ + pos = pos->prev) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** + * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_prev_safe(pos, n, head) \ + for (pos = (head)->prev, n = pos->prev; \ + pos != (head); \ + pos = n, n = pos->prev) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_reverse - iterate backwards over list of given type. + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_reverse(pos, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member)) + +/** + * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() + * @pos: the type * to use as a start point + * @head: the head of the list + * @member: the name of the list_struct within the struct. + * + * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). + */ +#define list_prepare_entry(pos, head, member) \ + ((pos) ? : list_entry(head, typeof(*pos), member)) + +/** + * list_for_each_entry_continue - continue iteration over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Continue to iterate over list of given type, continuing after + * the current position. + */ +#define list_for_each_entry_continue(pos, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_continue_reverse - iterate backwards from the given point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Start to iterate over list of given type backwards, continuing after + * the current position. + */ +#define list_for_each_entry_continue_reverse(pos, head, member) \ + for (pos = list_entry(pos->member.prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member)) + +/** + * list_for_each_entry_from - iterate over list of given type from the current point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type, continuing from current position. + */ +#define list_for_each_entry_from(pos, head, member) \ + for (; &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_continue + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type, continuing after current point, + * safe against removal of list entry. + */ +#define list_for_each_entry_safe_continue(pos, n, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_from + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type from current point, safe against + * removal of list entry. + */ +#define list_for_each_entry_safe_from(pos, n, head, member) \ + for (n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_reverse + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate backwards over list of given type, safe against removal + * of list entry. + */ +#define list_for_each_entry_safe_reverse(pos, n, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member), \ + n = list_entry(pos->member.prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.prev, typeof(*n), member)) + + +#endif diff --git a/com32/include/stdlib.h b/com32/include/stdlib.h index 14412972..f1989539 100644 --- a/com32/include/stdlib.h +++ b/com32/include/stdlib.h @@ -25,7 +25,6 @@ __extern long atol(const char *); __extern long long atoll(const char *); __extern __noreturn exit(int); __extern __noreturn _Exit(int); -__extern void free(void *); static __inline__ long labs(long __n) { return (__n < 0L) ? -__n : __n; @@ -40,6 +39,29 @@ __extern __mallocfunc void *malloc(size_t); __extern __mallocfunc void *zalloc(size_t); __extern __mallocfunc void *calloc(size_t, size_t); __extern __mallocfunc void *realloc(void *, size_t); +__extern int posix_memalign(void **memptr, size_t alignment, + size_t size); + +__extern void free(void *); + + +__extern void *__mem_get_tag_global(); +__extern void __mem_set_tag_global(void *tag); + +__extern void *__mem_get_tag(void *memptr); +__extern void __mem_set_tag(void *memptr, void *tag); + +__extern void __free_tagged(void *tag); + +static __inline__ void *__malloc_tagged(size_t size, void *tag) { + void *result = malloc(size); + __mem_set_tag(result, tag); + + return result; +} + + + __extern long strtol(const char *, char **, int); __extern long long strtoll(const char *, char **, int); __extern unsigned long strtoul(const char *, char **, int); diff --git a/com32/include/sys/elfcommon.h b/com32/include/sys/elfcommon.h index 2489e3c0..8d6ddb05 100644 --- a/com32/include/sys/elfcommon.h +++ b/com32/include/sys/elfcommon.h @@ -59,32 +59,108 @@ #define EM_S390_OLD 0xA390 /* Obsolete interrim value for S/390 */ /* Dynamic type values */ -#define DT_NULL 0 -#define DT_NEEDED 1 -#define DT_PLTRELSZ 2 -#define DT_PLTGOT 3 -#define DT_HASH 4 -#define DT_STRTAB 5 -#define DT_SYMTAB 6 -#define DT_RELA 7 -#define DT_RELASZ 8 -#define DT_RELAENT 9 -#define DT_STRSZ 10 -#define DT_SYMENT 11 -#define DT_INIT 12 -#define DT_FINI 13 -#define DT_SONAME 14 -#define DT_RPATH 15 -#define DT_SYMBOLIC 16 -#define DT_REL 17 -#define DT_RELSZ 18 -#define DT_RELENT 19 -#define DT_PLTREL 20 -#define DT_DEBUG 21 -#define DT_TEXTREL 22 -#define DT_JMPREL 23 -#define DT_LOPROC 0x70000000 -#define DT_HIPROC 0x7fffffff +#define DT_NULL 0 /* Marks end of dynamic section */ +#define DT_NEEDED 1 /* Name of needed library */ +#define DT_PLTRELSZ 2 /* Size in bytes of PLT relocs */ +#define DT_PLTGOT 3 /* Processor defined value */ +#define DT_HASH 4 /* Address of symbol hash table */ +#define DT_STRTAB 5 /* Address of string table */ +#define DT_SYMTAB 6 /* Address of symbol table */ +#define DT_RELA 7 /* Address of Rela relocs */ +#define DT_RELASZ 8 /* Total size of Rela relocs */ +#define DT_RELAENT 9 /* Size of one Rela reloc */ +#define DT_STRSZ 10 /* Size of string table */ +#define DT_SYMENT 11 /* Size of one symbol table entry */ +#define DT_INIT 12 /* Address of init function */ +#define DT_FINI 13 /* Address of termination function */ +#define DT_SONAME 14 /* Name of shared object */ +#define DT_RPATH 15 /* Library search path (deprecated) */ +#define DT_SYMBOLIC 16 /* Start symbol search here */ +#define DT_REL 17 /* Address of Rel relocs */ +#define DT_RELSZ 18 /* Total size of Rel relocs */ +#define DT_RELENT 19 /* Size of one Rel reloc */ +#define DT_PLTREL 20 /* Type of reloc in PLT */ +#define DT_DEBUG 21 /* For debugging; unspecified */ +#define DT_TEXTREL 22 /* Reloc might modify .text */ +#define DT_JMPREL 23 /* Address of PLT relocs */ +#define DT_BIND_NOW 24 /* Process relocations of object */ +#define DT_INIT_ARRAY 25 /* Array with addresses of init fct */ +#define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */ +#define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */ +#define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */ +#define DT_RUNPATH 29 /* Library search path */ +#define DT_FLAGS 30 /* Flags for the object being loaded */ +#define DT_ENCODING 32 /* Start of encoded range */ +#define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/ +#define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */ +#define DT_NUM 34 /* Number used */ +#define DT_LOOS 0x6000000d /* Start of OS-specific */ +#define DT_HIOS 0x6ffff000 /* End of OS-specific */ +#define DT_LOPROC 0x70000000 /* Start of processor-specific */ +#define DT_HIPROC 0x7fffffff /* End of processor-specific */ + +#define DT_VALRNGLO 0x6ffffd00 +#define DT_GNU_PRELINKED 0x6ffffdf5 /* Prelinking timestamp */ +#define DT_GNU_CONFLICTSZ 0x6ffffdf6 /* Size of conflict section */ +#define DT_GNU_LIBLISTSZ 0x6ffffdf7 /* Size of library list */ +#define DT_CHECKSUM 0x6ffffdf8 +#define DT_PLTPADSZ 0x6ffffdf9 +#define DT_MOVEENT 0x6ffffdfa +#define DT_MOVESZ 0x6ffffdfb +#define DT_FEATURE_1 0x6ffffdfc /* Feature selection (DTF_*). */ +#define DT_POSFLAG_1 0x6ffffdfd /* Flags for DT_* entries, effecting + the following DT_* entry. */ +#define DT_SYMINSZ 0x6ffffdfe /* Size of syminfo table (in bytes) */ +#define DT_SYMINENT 0x6ffffdff /* Entry size of syminfo */ +#define DT_VALRNGHI 0x6ffffdff +#define DT_VALTAGIDX(tag) (DT_VALRNGHI - (tag)) /* Reverse order! */ +#define DT_VALNUM 12 + +/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the + Dyn.d_un.d_ptr field of the Elf*_Dyn structure. + + If any adjustment is made to the ELF object after it has been + built these entries will need to be adjusted. */ +#define DT_ADDRRNGLO 0x6ffffe00 +#define DT_GNU_HASH 0x6ffffef5 /* GNU-style hash table. */ +#define DT_TLSDESC_PLT 0x6ffffef6 +#define DT_TLSDESC_GOT 0x6ffffef7 +#define DT_GNU_CONFLICT 0x6ffffef8 /* Start of conflict section */ +#define DT_GNU_LIBLIST 0x6ffffef9 /* Library list */ +#define DT_CONFIG 0x6ffffefa /* Configuration information. */ +#define DT_DEPAUDIT 0x6ffffefb /* Dependency auditing. */ +#define DT_AUDIT 0x6ffffefc /* Object auditing. */ +#define DT_PLTPAD 0x6ffffefd /* PLT padding. */ +#define DT_MOVETAB 0x6ffffefe /* Move table. */ +#define DT_SYMINFO 0x6ffffeff /* Syminfo table. */ +#define DT_ADDRRNGHI 0x6ffffeff +#define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */ +#define DT_ADDRNUM 11 + +/* The versioning entry types. The next are defined as part of the + GNU extension. */ +#define DT_VERSYM 0x6ffffff0 + +#define DT_RELACOUNT 0x6ffffff9 +#define DT_RELCOUNT 0x6ffffffa + +/* These were chosen by Sun. */ +#define DT_FLAGS_1 0x6ffffffb /* State flags, see DF_1_* below. */ +#define DT_VERDEF 0x6ffffffc /* Address of version definition + table */ +#define DT_VERDEFNUM 0x6ffffffd /* Number of version definitions */ +#define DT_VERNEED 0x6ffffffe /* Address of table with needed + versions */ +#define DT_VERNEEDNUM 0x6fffffff /* Number of needed versions */ +#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */ +#define DT_VERSIONTAGNUM 16 + +/* Sun added these machine-independent extensions in the "processor-specific" + range. Be compatible. */ +#define DT_AUXILIARY 0x7ffffffd /* Shared object to load before self */ +#define DT_FILTER 0x7fffffff /* Shared object to get values from */ +#define DT_EXTRATAGIDX(tag) ((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1) +#define DT_EXTRANUM 3 /* Auxilliary table entries */ #define AT_NULL 0 /* end of vector */ @@ -147,6 +223,52 @@ #define SHN_COMMON 0xfff2 #define SHN_HIRESERVE 0xffff +/* Symbol table definitions */ + +/* How to extract and insert information held in the st_info field. */ + +#define ELF32_ST_BIND(val) (((unsigned char) (val)) >> 4) +#define ELF32_ST_TYPE(val) ((val) & 0xf) +#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) + +/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field. */ +#define ELF64_ST_BIND(val) ELF32_ST_BIND (val) +#define ELF64_ST_TYPE(val) ELF32_ST_TYPE (val) +#define ELF64_ST_INFO(bind, type) ELF32_ST_INFO ((bind), (type)) + +/* Legal values for ST_BIND subfield of st_info (symbol binding). */ + +#define STB_LOCAL 0 /* Local symbol */ +#define STB_GLOBAL 1 /* Global symbol */ +#define STB_WEAK 2 /* Weak symbol */ +#define STB_NUM 3 /* Number of defined types. */ +#define STB_LOOS 10 /* Start of OS-specific */ +#define STB_HIOS 12 /* End of OS-specific */ +#define STB_LOPROC 13 /* Start of processor-specific */ +#define STB_HIPROC 15 /* End of processor-specific */ + +/* Legal values for ST_TYPE subfield of st_info (symbol type). */ + +#define STT_NOTYPE 0 /* Symbol type is unspecified */ +#define STT_OBJECT 1 /* Symbol is a data object */ +#define STT_FUNC 2 /* Symbol is a code object */ +#define STT_SECTION 3 /* Symbol associated with a section */ +#define STT_FILE 4 /* Symbol's name is file name */ +#define STT_COMMON 5 /* Symbol is a common data object */ +#define STT_TLS 6 /* Symbol is thread-local data object*/ +#define STT_NUM 7 /* Number of defined types. */ +#define STT_LOOS 10 /* Start of OS-specific */ +#define STT_HIOS 12 /* End of OS-specific */ +#define STT_LOPROC 13 /* Start of processor-specific */ +#define STT_HIPROC 15 /* End of processor-specific */ + + +/* Symbol table indices are found in the hash buckets and chain table + of a symbol hash table section. This special index value indicates + the end of a chain, meaning no further symbols are found in that bucket. */ + +#define STN_UNDEF 0 /* End of a chain. */ + /* Lenght of magic at the start of a file */ #define EI_NIDENT 16 @@ -184,4 +306,59 @@ #define ELFOSABI_NONE 0 #define ELFOSABI_LINUX 3 -#endif /* _SYS_ELFCOMMON_H */ +/* Intel 80386 specific definitions. */ + +/* i386 relocs. */ + +#define R_386_NONE 0 /* No reloc */ +#define R_386_32 1 /* Direct 32 bit */ +#define R_386_PC32 2 /* PC relative 32 bit */ +#define R_386_GOT32 3 /* 32 bit GOT entry */ +#define R_386_PLT32 4 /* 32 bit PLT address */ +#define R_386_COPY 5 /* Copy symbol at runtime */ +#define R_386_GLOB_DAT 6 /* Create GOT entry */ +#define R_386_JMP_SLOT 7 /* Create PLT entry */ +#define R_386_RELATIVE 8 /* Adjust by program base */ +#define R_386_GOTOFF 9 /* 32 bit offset to GOT */ +#define R_386_GOTPC 10 /* 32 bit PC relative offset to GOT */ +#define R_386_32PLT 11 +#define R_386_TLS_TPOFF 14 /* Offset in static TLS block */ +#define R_386_TLS_IE 15 /* Address of GOT entry for static TLS + block offset */ +#define R_386_TLS_GOTIE 16 /* GOT entry for static TLS block + offset */ +#define R_386_TLS_LE 17 /* Offset relative to static TLS + block */ +#define R_386_TLS_GD 18 /* Direct 32 bit for GNU version of + general dynamic thread local data */ +#define R_386_TLS_LDM 19 /* Direct 32 bit for GNU version of + local dynamic thread local data + in LE code */ +#define R_386_16 20 +#define R_386_PC16 21 +#define R_386_8 22 +#define R_386_PC8 23 +#define R_386_TLS_GD_32 24 /* Direct 32 bit for general dynamic + thread local data */ +#define R_386_TLS_GD_PUSH 25 /* Tag for pushl in GD TLS code */ +#define R_386_TLS_GD_CALL 26 /* Relocation for call to + __tls_get_addr() */ +#define R_386_TLS_GD_POP 27 /* Tag for popl in GD TLS code */ +#define R_386_TLS_LDM_32 28 /* Direct 32 bit for local dynamic + thread local data in LE code */ +#define R_386_TLS_LDM_PUSH 29 /* Tag for pushl in LDM TLS code */ +#define R_386_TLS_LDM_CALL 30 /* Relocation for call to + __tls_get_addr() in LDM code */ +#define R_386_TLS_LDM_POP 31 /* Tag for popl in LDM TLS code */ +#define R_386_TLS_LDO_32 32 /* Offset relative to TLS block */ +#define R_386_TLS_IE_32 33 /* GOT entry for negated static TLS + block offset */ +#define R_386_TLS_LE_32 34 /* Negated offset relative to static + TLS block */ +#define R_386_TLS_DTPMOD32 35 /* ID of module containing symbol */ +#define R_386_TLS_DTPOFF32 36 /* Offset in TLS block */ +#define R_386_TLS_TPOFF32 37 /* Negated offset in static TLS block */ +/* Keep this the last entry. */ +#define R_386_NUM 38 + +#endif /* _SYS_ELFCOMMON_H */ diff --git a/com32/include/sys/exec.h b/com32/include/sys/exec.h new file mode 100644 index 00000000..7b3a9a0c --- /dev/null +++ b/com32/include/sys/exec.h @@ -0,0 +1,113 @@ +/* + * exec.h + * + * Created on: Aug 14, 2008 + * Author: Stefan Bucur <stefanb@zytor.com> + */ + +#ifndef EXEC_H_ +#define EXEC_H_ + +#include <sys/module.h> + +/** + * EXEC_ROOT_NAME - The name of the ELF module associated with the COM32 module. + * + * This is a shallow ELF module, that contains only the symbol table for + * the code and data sections of the loaded COM32 root module. + */ +#define EXEC_ROOT_NAME "_root_.dyn" + +/** + * EXEC_DIRECTORY - The base path for all dynamic linked modules. + */ +#define EXEC_DIRECTORY "/dyn/" + +/** + * exec_init - Initialize the dynamic execution environment. + * + * Among others, it initializes the module subsystem and loads the root + * module into memory. You should note the difference between the module + * management API, and the execution API: + * - the module system is a static one - it only manages the data structures + * and their relationship. It does not describe the way modules are executed, + * when and how they are loaded/unloaded, etc. It acts as a service layer for + * the execution API. + * - the execution environment is the dynamic part of the SYSLINUX dynamic + * module API - it implements the behavior of the modules: it + * triggers the execution of initialization and termination functions for + * libraries, executes the modules marked as executable, handles dynamic + * memory cleanup, etc. In other words, at this layer the code and data + * loaded by the lower module layer gets to be executed by the CPU, + * thus becoming part of the SYSLINUX environment. + */ +extern int exec_init(); + + +/** + * load_library - Loads a dynamic library into the environment. + * @name: the name of the library to load, including the extension + * (e.g. 'sort.dyn') + * + * A dynamic library is an ELF module that may contain initialization and + * termination routines, but not a main routine. At the same time, any memory + * allocations using malloc() and its derivatives are made on behalf of the + * currently executing program or the COM32 root module. If the library + * is unloaded, no memory cleanup is performed. + */ +extern int load_library(const char *name); + +/** + * unload_library - unloads a library from the environment. + * @name: the name of the library to unload, including the extension + * (e.g. 'sort.dyn') + * + * Note that no memory allocated by the library code is cleaned up, as the + * allocations belong to the innermost calling program in the call stack. + */ +extern int unload_library(const char *name); + +/** + * spawnv - Executes a program in the current environment. + * @name: the name of the program to spawn, including the extension + * (e.g. 'hello.dyn') + * @argv: a NULL-terminated vector of string arguments, starting with + * the program name. + * + * A program is an ELF module that contains a main routine. A program is + * loaded into memory, executed, then unloaded, thus remaining in memory only + * while the main() function is executing. A program also defines a + * memory allocation context, and a simple garbage collection mechanism + * it thus provided. This is done by internally associating with the program + * module each pointer returned by malloc(). After the program finishes + * its execution, all the unallocated memory pertaining to the program + * is automatically cleaned up. + * + * Note that this association takes place both for the allocations happening + * directly in the program, or indirectly through a library function. Libraries + * do not create allocation contexts, thus each allocation they made belong + * to the innermost calling program. + */ +extern int spawnv(const char *name, const char **argv); + +/** + * spawnl - Executes a program in the current environment. + * @name: the name of the program to spawn, including the extension + * (e.g. 'hello.dyn') + * @arg: the first argument (argv[0]) to be passed to the main function + * of the program + * @...: optional subsequent arguments that are passed o the main function + * of the program + * + * This is another version of the spawn routine. Please see 'spawnv' for + * a full presentation. + */ +extern int spawnl(const char *name, const char *arg, ...); + +/** + * exec_term - Releases the resources of the execution environment. + */ +extern void exec_term(); + + +#endif /* EXEC_H_ */ diff --git a/com32/include/sys/module.h b/com32/include/sys/module.h new file mode 100644 index 00000000..e09f1bf8 --- /dev/null +++ b/com32/include/sys/module.h @@ -0,0 +1,317 @@ +/** + * syslinux/module.h + * + * Dynamic ELF modules definitions and services. + */ + + +#ifndef MODULE_H_ +#define MODULE_H_ + +#include <stdio.h> +#include <elf.h> +#include <stdint.h> +#include <linux/list.h> + + +/* + * The maximum length of the module file name (including path), stored + * in the struct module descriptor. + */ +#define MODULE_NAME_SIZE 64 + +/* + * Initialization and finalization function signatures + */ + + +/** + * module_init_t - pointer to a initialization routine + * + * The initialization routine is called after all module constructors were invoked. + * It takes no parameters and returns 0 if the module was initialized successfully, + * or a non-zero value if errors have occurred. + */ +typedef int (*module_init_t)(void); + +/** + * module_exit_t - pointer to a finalization routine + * + * The finalization routine is called before the module destructors are to be invoked. + * It simply executes some cleanup code, without error reporting. + */ +typedef void (*module_exit_t)(void); + +/** + * module_main_t - pointer to an entry routine + * + * The entry routine is present only in executable modules, and represent + * the entry point for the program. + */ +typedef int (*module_main_t)(int, char**); + + +/** + * struct elf_module - structure encapsulating a module loaded in memory. + * + * Each SYSLINUX ELF module must have an associated struct elf_module descriptor + * that keeps track of memory allocations, symbol information, and various other + * resources needed by the module itself or by other modules that depend on it. + * + * There are two types of modules: + * - regular modules, which are actual memory images of a loaded & linked shared + * object (ELF file). Memory is reserved for the struct elf_module structure itself + * and for the object loadable sections read from the file. + * - shallow modules, which are not associated with an ELF shared object, but contain + * metainformation about a memory region already present and containing the + * actual code and data. One particular usage of shallow modules is to access + * symbol information from the root COM32 module loaded by the SYSLINUX core. + * As their name suggests, memory is reserved only for the elf_module structure + * itself and optionally for a usually small memory region containing metainformation + * (symbol information). + * + * Module descriptors are related to each other through dependency information. A module + * can depend on symbols from other modules, and in turn it can provide symbols used + * by other dependant modules. This relationship can be described as a directed + * acyclic graph (DAG). The graph is stored using double linked lists of + * predecessors and successors. There is also a global linked list containing all + * the modules currently loaded. + */ +struct elf_module { + char name[MODULE_NAME_SIZE]; // The module name + + int shallow; // Whether the module contains any code + + struct list_head required; // Head of the required modules list + struct list_head dependants; // Head of module dependants list + struct list_head list; // The list entry in the module list + + module_init_t *init_func; // The initialization entry point + module_exit_t *exit_func; // The module finalization code + module_main_t *main_func; // The main function (for executable modules) + + + void *module_addr; // The module location in the memory + Elf32_Addr base_addr; // The base address of the module + Elf32_Word module_size; // The module size in memory + + Elf32_Word *hash_table; // The symbol hash table + Elf32_Word *ghash_table; // The GNU style hash table + char *str_table; // The string table + void *sym_table; // The symbol table + void *got; // The Global Offset Table + Elf32_Dyn *dyn_table; // Dynamic loading information table + + Elf32_Word strtable_size; // The size of the string table + Elf32_Word syment_size; // The size of a symbol entry + Elf32_Word symtable_size; // The size of the symbol table + + + // Transient - Data available while the module is loading + FILE *_file; // The file object of the open file + Elf32_Off _cr_offset; // The current offset in the open file +}; + +/** + * struct module_dep - structure encapsulating a module dependency need + * + * This structure represents an item in a double linked list of predecessors or + * successors. The item contents is a pointer to the corresponding module descriptor. + */ +struct module_dep { + struct list_head list; // The list entry in the dependency list + + struct elf_module *module; // The target module descriptor +}; + + + +#ifdef DYNAMIC_MODULE + +/* + * This portion is included by dynamic (ELF) module source files. + */ + +#define MODULE_INIT(fn) static module_init_t __module_init \ + __used __attribute__((section(".ctors_modinit"))) = fn + +#define MODULE_EXIT(fn) static module_exit_t __module_exit \ + __used __attribute__((section(".dtors_modexit"))) = fn + +#define MODULE_MAIN(fn) static module_main_t __module_main \ + __used __attribute__((section(".ctors_modmain"))) = fn + +#else + +/* + * This portion is included by the core COM32 module. + */ + +/* + * Accepted values for various ELF header parameters found in an ELF dynamic + * object. + */ +#define MODULE_ELF_CLASS ELFCLASS32 // 32-bit modules +#define MODULE_ELF_CLASS_SIZE 32 // Size of a word value +#define MODULE_ELF_DATA ELFDATA2LSB // Word endianess +#define MODULE_ELF_VERSION EV_CURRENT // Object version +#define MODULE_ELF_TYPE ET_DYN // Executable type (shared object - .so) +#define MODULE_ELF_MACHINE EM_386 // Target architecture + +/** + * Names of symbols with special meaning (treated as special cases at linking) + */ +#define MODULE_ELF_INIT_PTR "__module_init_ptr" // Initialization pointer symbol name +#define MODULE_ELF_EXIT_PTR "__module_exit_ptr" // Finalization pointer symbol name +#define MODULE_ELF_MAIN_PTR "__module_main_ptr" // Entry pointer symbol name + +/** + * modules_head - A global linked list containing all the loaded modules. + */ +extern struct list_head modules_head; + + +/** + * for_each_module - iterator loop through the list of loaded modules. + */ +#define for_each_module(m) list_for_each_entry(m, &modules_head, list) + +/** + * modules_init - initialize the module subsystem. + * + * This function must be called before any module operation is to be performed. + */ +extern int modules_init(void); + + +/** + * modules_term - releases all resources pertaining to the module subsystem. + * + * This function should be called after all module operations. + */ +extern void modules_term(void); + + +/** + * module_alloc - reserves space for a new module descriptor. + * @name: the file name of the module to be loaded. + * + * The function simply allocates a new module descriptor and initializes its fields + * in order to be used by subsequent loading operations. + */ +extern struct elf_module *module_alloc(const char *name); + + +/** + * module_load - loads a regular ELF module into memory. + * @module: the module descriptor returned by module_alloc. + * + * The function reads the module file, checks whether the file has a + * valid structure, then loads into memory the code and the data and performs + * any symbol relocations. A module dependency is created automatically when the + * relocated symbol is defined in a different module. + * + * The function returns 0 if the operation is completed successfully, and + * a non-zero value if an error occurs. Possible errors include invalid module + * structure, missing symbol definitions (unsatisfied dependencies) and memory + * allocation issues. + */ +extern int module_load(struct elf_module *module); + + +/** + * module_load_shallow - loads a shallow ELF module into memory. + * @module: the module descriptor returned by module_alloc. + * + * The function reads the module file, checks whether the file has a valid + * structure, then loads into memory the module metadata. The metadata currently + * contains a symbol table that describes code & data allocated by other means. + * Its current use is to describe the root COM32 module to the rest of the + * module subsystem. + */ +extern int module_load_shallow(struct elf_module *module); + +/** + * module_unload - unloads the module from the system. + * @module: the module descriptor structure. + * + * The function checks to see whether the module can be safely removed, then + * it releases all the associated memory. This function can be applied both + * for standard modules and for shallow modules. + * + * A module can be safely removed from the system when no other modules reference + * symbols from it. + */ +extern int module_unload(struct elf_module *module); + +/** + * module_unloadable - checks whether the given module can be unloaded. + * @module: the module descriptor structure + * + * A module can be unloaded from the system when no other modules depend on it, + * that is, no symbols are referenced from it. + */ +extern int module_unloadable(struct elf_module *module); + +/** + * module_find - searches for a module by its name. + * @name: the name of the module, as it was specified in module_alloc. + * + * The function returns a pointer to the module descriptor, if found, or + * NULL otherwise. + */ +extern struct elf_module *module_find(const char *name); + +/** + * module_find_symbol - searches for a symbol definition in a given module. + * @name: the name of the symbol to be found. + * @module: the module descriptor structure. + * + * The function searches the module symbol table for a symbol matching exactly + * the name provided. The operation uses the following search algorithms, in this + * order: + * - If a GNU hash table is present in the module, it is used to find the symbol. + * - If the symbol cannot be found with the first method (either the hash table + * is not present or the symbol is not found) and if a regular (SysV) hash table + * is present, a search is performed on the SysV hash table. If the symbol is not + * found, NULL is returned. + * - If the second method cannot be applied, a linear search is performed by + * inspecting every symbol in the symbol table. + * + * If the symbol is found, a pointer to its descriptor structure is returned, and + * NULL otherwise. + */ +extern Elf32_Sym *module_find_symbol(const char *name, struct elf_module *module); + +/** + * global_find_symbol - searches for a symbol definition in the entire module namespace. + * @name: the name of the symbol to be found. + * @module: an optional (may be NULL) pointer to a module descriptor variable that + * will hold the module where the symbol was found. + * + * The function search for the given symbol name in all the modules currently + * loaded in the system, in the reverse module loading order. That is, the most + * recently loaded module is searched first, followed by the previous one, until + * the first loaded module is reached. + * + * If no module contains the symbol, NULL is returned, otherwise the return value is + * a pointer to the symbol descriptor structure. If the module parameter is not NULL, + * it is filled with the address of the module descriptor where the symbol is defined. + */ +extern Elf32_Sym *global_find_symbol(const char *name, struct elf_module **module); + +/** + * module_get_absolute - converts an memory address relative to a module base address + * to its absolute value in RAM. + * @addr: the relative address to convert. + * @module: the module whose base address is used for the conversion. + * + * The function returns a pointer to the absolute memory address. + */ +static inline void *module_get_absolute(Elf32_Addr addr, struct elf_module *module) { + return (void*)(module->base_addr + addr); +} + +#endif // DYNAMIC_MODULE + +#endif // MODULE_H_ diff --git a/com32/lib/Makefile b/com32/lib/Makefile index 5e0e15ae..57348a8d 100644 --- a/com32/lib/Makefile +++ b/com32/lib/Makefile @@ -7,7 +7,107 @@ NOGPL := 1 topdir = ../.. include MCONFIG -LIBOBJS = \ +## OPTIONAL OBJECTS, AVAILABLE AS DYNAMIC LINKED MODULES +# PNG library object files +LIBPNG_OBJS = \ + libpng/png.o libpng/pngset.o libpng/pngget.o libpng/pngrutil.o \ + libpng/pngtrans.o libpng/pngwutil.o libpng/pngread.o \ + libpng/pngrio.o libpng/pngwio.o libpng/pngwrite.o \ + libpng/pngrtran.o libpng/pngwtran.o libpng/pngmem.o \ + libpng/pngerror.o libpng/pngpread.o + +# ZIP library object files +LIBZLIB_OBJS = \ + zlib/adler32.o zlib/compress.o zlib/crc32.o zlib/gzio.o \ + zlib/uncompr.o zlib/deflate.o zlib/trees.o zlib/zutil.o \ + zlib/inflate.o zlib/infback.o zlib/inftrees.o zlib/inffast.o\ + \ + sys/zfile.o sys/zfopen.o \ + \ + syslinux/zloadfile.o + +# JPG library object files +LIBJPG_OBJS = \ + jpeg/tinyjpeg.o jpeg/jidctflt.o jpeg/decode1.o jpeg/decode3.o \ + jpeg/rgb24.o jpeg/bgr24.o jpeg/yuv420p.o jpeg/grey.o \ + jpeg/rgba32.o jpeg/bgra32.o + +LIBVESA_OBJS = \ + sys/vesacon_write.o sys/vesaserial_write.o \ + sys/vesa/initvesa.o sys/vesa/drawtxt.o sys/vesa/background.o \ + sys/vesa/alphatbl.o sys/vesa/screencpy.o sys/vesa/fmtpixel.o + +LIBPCI_OBJS = \ + pci/cfgtype.o pci/scan.o \ + pci/readb.o pci/readw.o pci/readl.o pci/readbios.o \ + pci/writeb.o pci/writew.o pci/writel.o pci/writebios.o + +LIBSYSLINUX_OBJS = \ + syslinux/reboot.o syslinux/keyboard.o \ + syslinux/features.o syslinux/config.o \ + syslinux/ipappend.o syslinux/dsinfo.o syslinux/version.o \ + \ + syslinux/addlist.o syslinux/freelist.o syslinux/memmap.o \ + syslinux/movebits.o syslinux/shuffle.o syslinux/shuffle_pm.o \ + syslinux/shuffle_rm.o syslinux/zonelist.o \ + syslinux/dump_mmap.o syslinux/dump_movelist.o \ + \ + syslinux/run_default.o syslinux/run_command.o \ + syslinux/cleanup.o syslinux/localboot.o syslinux/runimage.o \ + \ + syslinux/loadfile.o syslinux/floadfile.o \ + \ + syslinux/load_linux.o syslinux/initramfs.o \ + syslinux/initramfs_file.o syslinux/initramfs_loadfile.o \ + syslinux/initramfs_archive.o \ + \ + syslinux/pxe_get_cached.o syslinux/pxe_get_nic.o \ + \ + syslinux/adv.o syslinux/advwrite.o syslinux/getadv.o \ + syslinux/setadv.o + + +## CORE OBJECTS, INCLUDED IN THE ROOT COM32 MODULE +LIBENTRY_OBJS = \ + sys/intcall.o sys/farcall.o sys/cfarcall.o sys/zeroregs.o \ + sys/entry.o sys/exit.o sys/argv.o sys/times.o \ + sys/fileinfo.o sys/opendev.o sys/read.o sys/write.o sys/ftell.o \ + sys/close.o sys/open.o sys/fileread.o sys/fileclose.o \ + sys/isatty.o sys/fstat.o \ + \ + syslinux/idle.o + +LIBMODULE_OBJS = \ + sys/module/common.o sys/module/elf_module.o \ + sys/module/shallow_module.o sys/module/elfutils.o \ + sys/module/exec.o + + + +LIBGCC_OBJS = \ + libgcc/__ashldi3.o libgcc/__udivdi3.o \ + libgcc/__negdi2.o libgcc/__ashrdi3.o libgcc/__lshrdi3.o \ + libgcc/__muldi3.o libgcc/__udivmoddi4.o libgcc/__umoddi3.o \ + libgcc/__divdi3.o libgcc/__moddi3.o + +LIBCONSOLE_OBJS = \ + \ + sys/openconsole.o sys/line_input.o \ + sys/colortable.o sys/screensize.o \ + \ + sys/stdcon_read.o sys/stdcon_write.o sys/rawcon_read.o \ + sys/rawcon_write.o sys/err_read.o sys/err_write.o \ + sys/null_read.o sys/null_write.o sys/serial_write.o \ + \ + sys/xserial_write.o \ + \ + sys/ansi.o \ + \ + sys/ansicon_write.o sys/ansiserial_write.o \ + \ + syslinux/serial.o + +LIBOTHER_OBJS = \ abort.o atexit.o atoi.o atol.o atoll.o calloc.o creat.o \ ctypes.o errno.o fgetc.o fgets.o fopen.o fprintf.o fputc.o \ fclose.o putchar.o setjmp.o \ @@ -16,9 +116,9 @@ LIBOBJS = \ memcpy.o mempcpy.o memmem.o memmove.o memset.o memswap.o \ exit.o onexit.o \ perror.o printf.o puts.o qsort.o realloc.o seed48.o snprintf.o \ - sprintf.o srand48.o sscanf.o stack.o strcasecmp.o strcat.o \ - strchr.o strcmp.o strcpy.o strpcpy.o strdup.o strlen.o \ - strerror.o strnlen.o \ + sprintf.o srand48.o sscanf.o strcasecmp.o strcat.o \ + strchr.o strcmp.o strcpy.o strdup.o strerror.o strlen.o \ + strnlen.o strpcpy.o \ strncasecmp.o strncat.o strncmp.o strncpy.o strndup.o \ stpcpy.o stpncpy.o \ strntoimax.o strntoumax.o strrchr.o strsep.o strspn.o strstr.o \ @@ -34,14 +134,6 @@ LIBOBJS = \ libgcc/__muldi3.o libgcc/__udivmoddi4.o libgcc/__umoddi3.o \ libgcc/__divdi3.o libgcc/__moddi3.o \ \ - sys/intcall.o sys/farcall.o sys/cfarcall.o sys/zeroregs.o \ - sys/entry.o sys/exit.o sys/argv.o sys/times.o \ - sys/fileinfo.o sys/opendev.o sys/read.o sys/write.o sys/ftell.o \ - sys/close.o sys/open.o sys/fileread.o sys/fileclose.o \ - sys/isatty.o sys/fstat.o \ - \ - sys/zfile.o sys/zfopen.o \ - \ sys/openconsole.o sys/line_input.o \ sys/colortable.o sys/screensize.o \ \ @@ -55,55 +147,32 @@ LIBOBJS = \ \ sys/ansicon_write.o sys/ansiserial_write.o \ \ - sys/vesacon_write.o sys/vesaserial_write.o \ - sys/vesa/initvesa.o sys/vesa/drawtxt.o sys/vesa/background.o \ - sys/vesa/alphatbl.o sys/vesa/screencpy.o sys/vesa/fmtpixel.o \ - \ pci/cfgtype.o pci/scan.o \ pci/readb.o pci/readw.o pci/readl.o pci/readbios.o \ pci/writeb.o pci/writew.o pci/writel.o pci/writebios.o \ \ - zlib/adler32.o zlib/compress.o zlib/crc32.o zlib/gzio.o \ - zlib/uncompr.o zlib/deflate.o zlib/trees.o zlib/zutil.o \ - zlib/inflate.o zlib/infback.o zlib/inftrees.o zlib/inffast.o \ - \ - libpng/png.o libpng/pngset.o libpng/pngget.o libpng/pngrutil.o \ - libpng/pngtrans.o libpng/pngwutil.o libpng/pngread.o \ - libpng/pngrio.o libpng/pngwio.o libpng/pngwrite.o \ - libpng/pngrtran.o libpng/pngwtran.o libpng/pngmem.o \ - libpng/pngerror.o libpng/pngpread.o \ - \ - jpeg/tinyjpeg.o jpeg/jidctflt.o jpeg/decode1.o jpeg/decode3.o \ - jpeg/rgb24.o jpeg/bgr24.o jpeg/yuv420p.o jpeg/grey.o \ - jpeg/rgba32.o jpeg/bgra32.o \ - \ - sys/x86_init_fpu.o math/pow.o math/strtod.o \ - \ - syslinux/idle.o syslinux/reboot.o \ - syslinux/features.o syslinux/config.o syslinux/serial.o \ - syslinux/ipappend.o syslinux/dsinfo.o syslinux/version.o \ - syslinux/keyboard.o \ - \ - syslinux/memscan.o \ - \ - syslinux/addlist.o syslinux/freelist.o syslinux/memmap.o \ - syslinux/movebits.o syslinux/shuffle.o syslinux/shuffle_pm.o \ - syslinux/shuffle_rm.o syslinux/zonelist.o \ - syslinux/dump_mmap.o syslinux/dump_movelist.o \ - \ - syslinux/run_default.o syslinux/run_command.o \ - syslinux/cleanup.o syslinux/localboot.o syslinux/runimage.o \ - \ - syslinux/loadfile.o syslinux/floadfile.o syslinux/zloadfile.o \ - \ - syslinux/load_linux.o syslinux/initramfs.o \ - syslinux/initramfs_file.o syslinux/initramfs_loadfile.o \ - syslinux/initramfs_archive.o \ - \ - syslinux/pxe_get_cached.o syslinux/pxe_get_nic.o \ - \ - syslinux/adv.o syslinux/advwrite.o syslinux/getadv.o \ - syslinux/setadv.o + sys/x86_init_fpu.o math/pow.o math/strtod.o + +MINLIBOBJS = \ + $(LIBOTHER_OBJS) \ + $(LIBENTRY_OBJS) \ + $(LIBGCC_OBJS) \ + $(LIBCONSOLE_OBJS) \ + $(LIBMODULE_OBJS) + + +DYNLIBOBJS = \ + $(LIBZLIB_OBJS) \ + $(LIBPNG_OBJS) \ + $(LIBJPG_OBJS) \ + $(LIBPCI_OBJS) \ + $(LIBVESA_OBJS) \ + $(LIBSYSLINUX_OBJS) + + +LIBOBJS = \ + $(MINLIBOBJS) \ + $(DYNLIBOBJS) BINDIR = /usr/bin LIBDIR = /usr/lib @@ -112,18 +181,31 @@ AUXDIR = $(DATADIR)/syslinux INCDIR = /usr/include COM32DIR = $(AUXDIR)/com32 -all: libcom32.a +all: libcom32.a libcom32min.a klibc.dyn libcom32.a : $(LIBOBJS) rm -f $@ $(AR) cq $@ $^ $(RANLIB) $@ + +$(LIBMODULE_OBJS) : CFLAGS += -DELF_DEBUG +libcom32min.a : $(MINLIBOBJS) + rm -f $@ + $(AR) cq $@ $^ + $(RANLIB) $@ -tidy dist clean: +klibc.dyn : $(DYNLIBOBJS) + rm -f $@ + $(LD) -shared -T elf32.ld -o $@ $(DYNLIBOBJS) + +tidy dist: rm -f sys/vesa/alphatbl.c find . \( -name \*.o -o -name \*.a -o -name .\*.d -o -name \*.tmp \) -print0 | \ xargs -0r rm -f +clean: tidy + rm -f *.a *.dyn + spotless: clean rm -f *.a rm -f *~ \#* */*~ */\#* diff --git a/com32/lib/elf32.ld b/com32/lib/elf32.ld new file mode 100644 index 00000000..e41f9c91 --- /dev/null +++ b/com32/lib/elf32.ld @@ -0,0 +1,184 @@ +/* + * Linker script for ELF dynamic loaded modules. + */ + +/* Script for --shared -z combreloc: shared library, combine & sort relocs */ +OUTPUT_FORMAT("elf32-i386", "elf32-i386", + "elf32-i386") +OUTPUT_ARCH(i386) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0 + SIZEOF_HEADERS; + .note.gnu.build-id : { *(.note.gnu.build-id) } + .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.dyn : + { + *(.rel.init) + *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) + *(.rel.fini) + *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) + *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*) + *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) + *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) + *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) + *(.rel.ctors) + *(.rel.dtors) + *(.rel.got) + *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) + } + .rela.dyn : + { + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : + { + KEEP (*(.init)) + } =0x90909090 + .plt : { *(.plt) } + .text : + { + *(.text .stub .text.* .gnu.linkonce.t.*) + KEEP (*(.text.*personality*)) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + } =0x90909090 + .fini : + { + KEEP (*(.fini)) + } =0x90909090 + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + . = ALIGN(4); + .preinit_array : + { + KEEP (*(.preinit_array)) + } + .init_array : + { + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + } + .fini_array : + { + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + } + + .ctors : + { + __ctors_start = .; + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + LONG(0x00000000) + __module_init_ptr = .; + KEEP (*(.ctors_modinit)) + LONG(0x00000000) + __module_main_ptr = .; + KEEP (*(.ctors_modmain)) + LONG(0x00000000) + } + + .dtors : + { + __dtors_start = .; + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + LONG(0x00000000) + __module_exit_ptr = .; + KEEP (*(.dtors_modexit)) + LONG(0x00000000) + } + + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) } + .dynamic : { *(.dynamic) } + .got : { *(.got) } + /*. = DATA_SEGMENT_RELRO_END (12, .); -> This gives a "invalid assignment to location counter" error */ + .got.plt : { *(.got.plt) } + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + KEEP (*(.gnu.linkonce.d.*personality*)) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + PROVIDE (edata = .); + PROVIDE (_edata = .); + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. + FIXME: Why do we need it? When there is no .bss section, we don't + pad the .data section. */ + . = ALIGN(. != 0 ? 32 / 8 : 1); + } + . = ALIGN(32 / 8); + . = ALIGN(32 / 8); + PROVIDE (_end = .); + PROVIDE (end = .); + /*. = DATA_SEGMENT_END (.); -> This gives a "invalid assignment to location counter" error */ + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* DWARF 3 */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } + /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) } +} diff --git a/com32/lib/free.c b/com32/lib/free.c index be23865a..f8a2e1f4 100644 --- a/com32/lib/free.c +++ b/com32/lib/free.c @@ -7,49 +7,52 @@ #include <stdlib.h> #include "malloc.h" -static struct free_arena_header *__free_block(struct free_arena_header *ah) -{ +static struct free_arena_header * + __free_block(struct free_arena_header *ah) { struct free_arena_header *pah, *nah; pah = ah->a.prev; nah = ah->a.next; - if (pah->a.type == ARENA_TYPE_FREE && - (char *)pah + pah->a.size == (char *)ah) { - /* Coalesce into the previous block */ - pah->a.size += ah->a.size; - pah->a.next = nah; - nah->a.prev = pah; + if ( ARENA_TYPE_GET(pah->a.attrs) == ARENA_TYPE_FREE && + (char *)pah+ARENA_SIZE_GET(pah->a.attrs) == (char *)ah ) { + /* Coalesce into the previous block */ + ARENA_SIZE_SET(pah->a.attrs, ARENA_SIZE_GET(pah->a.attrs) + + ARENA_SIZE_GET(ah->a.attrs)); + pah->a.next = nah; + nah->a.prev = pah; #ifdef DEBUG_MALLOC - ah->a.type = ARENA_TYPE_DEAD; + ARENA_TYPE_SET(ah->a.attrs, ARENA_TYPE_DEAD); #endif - ah = pah; - pah = ah->a.prev; + ah = pah; + pah = ah->a.prev; } else { - /* Need to add this block to the free chain */ - ah->a.type = ARENA_TYPE_FREE; - - ah->next_free = __malloc_head.next_free; - ah->prev_free = &__malloc_head; - __malloc_head.next_free = ah; - ah->next_free->prev_free = ah; + /* Need to add this block to the free chain */ + ARENA_TYPE_SET(ah->a.attrs, ARENA_TYPE_FREE); + ah->a.tag = NULL; + + ah->next_free = __malloc_head.next_free; + ah->prev_free = &__malloc_head; + __malloc_head.next_free = ah; + ah->next_free->prev_free = ah; } /* In either of the previous cases, we might be able to merge with the subsequent block... */ - if (nah->a.type == ARENA_TYPE_FREE && - (char *)ah + ah->a.size == (char *)nah) { - ah->a.size += nah->a.size; + if ( ARENA_TYPE_GET(nah->a.attrs) == ARENA_TYPE_FREE && + (char *)ah+ARENA_SIZE_GET(ah->a.attrs) == (char *)nah ) { + ARENA_SIZE_SET(ah->a.attrs, ARENA_SIZE_GET(ah->a.attrs) + + ARENA_SIZE_GET(nah->a.attrs)); - /* Remove the old block from the chains */ - nah->next_free->prev_free = nah->prev_free; - nah->prev_free->next_free = nah->next_free; - ah->a.next = nah->a.next; - nah->a.next->a.prev = ah; + /* Remove the old block from the chains */ + nah->next_free->prev_free = nah->prev_free; + nah->prev_free->next_free = nah->next_free; + ah->a.next = nah->a.next; + nah->a.next->a.prev = ah; #ifdef DEBUG_MALLOC - nah->a.type = ARENA_TYPE_DEAD; + ARENA_TYPE_SET(nah->a.attrs, ARENA_TYPE_DEAD); #endif } @@ -57,57 +60,36 @@ static struct free_arena_header *__free_block(struct free_arena_header *ah) return ah; } -/* - * This is used to insert a block which is not previously on the - * free list. Only the a.size field of the arena header is assumed - * to be valid. - */ -void __inject_free_block(struct free_arena_header *ah) -{ - struct free_arena_header *nah; - size_t a_end = (size_t) ah + ah->a.size; - size_t n_end; - - for (nah = __malloc_head.a.next; nah->a.type != ARENA_TYPE_HEAD; - nah = nah->a.next) { - n_end = (size_t) nah + nah->a.size; - - /* Is nah entirely beyond this block? */ - if ((size_t) nah >= a_end) - break; - - /* Is this block entirely beyond nah? */ - if ((size_t) ah >= n_end) - continue; - - /* Otherwise we have some sort of overlap - reject this block */ - return; - } - - /* Now, nah should point to the successor block */ - ah->a.next = nah; - ah->a.prev = nah->a.prev; - nah->a.prev = ah; - ah->a.prev->a.next = ah; - - __free_block(ah); -} - void free(void *ptr) { struct free_arena_header *ah; - if (!ptr) - return; + if ( !ptr ) + return; ah = (struct free_arena_header *) - ((struct arena_header *)ptr - 1); + ((struct arena_header *)ptr - 1); #ifdef DEBUG_MALLOC - assert(ah->a.type == ARENA_TYPE_USED); + assert( ARENA_TYPE_GET(ah->a.attrs) == ARENA_TYPE_USED ); #endif __free_block(ah); - /* Here we could insert code to return memory to the system. */ + /* Here we could insert code to return memory to the system. */ +} + +void __free_tagged(void *tag) { + struct free_arena_header *fp, *nfp; + + for (fp = __malloc_head.a.next, nfp = fp->a.next; + ARENA_TYPE_GET(fp->a.attrs) != ARENA_TYPE_HEAD; + fp = nfp, nfp = fp->a.next) { + + if (ARENA_TYPE_GET(fp->a.attrs) == ARENA_TYPE_USED && + fp->a.tag == tag) { + // Free this block + __free_block(fp); + } + } } diff --git a/com32/lib/malloc.c b/com32/lib/malloc.c index ec103ab3..4b113221 100644 --- a/com32/lib/malloc.c +++ b/com32/lib/malloc.c @@ -5,19 +5,26 @@ */ #include <stdlib.h> +#include <errno.h> #include <string.h> #include <com32.h> #include <syslinux/memscan.h> #include "init.h" #include "malloc.h" -struct free_arena_header __malloc_head = { - { - ARENA_TYPE_HEAD, - 0, - &__malloc_head, - &__malloc_head, - }, +/** + * The global tag used to label all the new allocations + */ +static void *__global_tag = NULL; + +struct free_arena_header __malloc_head = +{ + { + NULL, + ARENA_TYPE_HEAD, + &__malloc_head, + &__malloc_head + }, &__malloc_head, &__malloc_head }; @@ -81,7 +88,9 @@ static void __constructor init_memory_arena(void) __stack_size = total_space - 4 * sizeof(struct arena_header); fp = (struct free_arena_header *)start; - fp->a.size = total_space - __stack_size; + ARENA_TYPE_SET(fp->a.attrs, ARENA_TYPE_FREE); + ARENA_SIZE_SET(fp->a.attrs, total_space - __stack_size); + fp->a.tag = NULL; __inject_free_block(fp); @@ -97,37 +106,40 @@ static void *__malloc_from_block(struct free_arena_header *fp, size_t size) size_t fsize; struct free_arena_header *nfp, *na; - fsize = fp->a.size; + fsize = ARENA_SIZE_GET(fp->a.attrs); /* We need the 2* to account for the larger requirements of a free block */ - if (fsize >= size + 2 * sizeof(struct arena_header)) { - /* Bigger block than required -- split block */ - nfp = (struct free_arena_header *)((char *)fp + size); - na = fp->a.next; - - nfp->a.type = ARENA_TYPE_FREE; - nfp->a.size = fsize - size; - fp->a.type = ARENA_TYPE_USED; - fp->a.size = size; - - /* Insert into all-block chain */ - nfp->a.prev = fp; - nfp->a.next = na; - na->a.prev = nfp; - fp->a.next = nfp; - - /* Replace current block on free chain */ - nfp->next_free = fp->next_free; - nfp->prev_free = fp->prev_free; - fp->next_free->prev_free = nfp; - fp->prev_free->next_free = nfp; + if ( fsize >= size+2*sizeof(struct arena_header) ) { + /* Bigger block than required -- split block */ + nfp = (struct free_arena_header *)((char *)fp + size); + na = fp->a.next; + + ARENA_TYPE_SET(nfp->a.attrs, ARENA_TYPE_FREE); + ARENA_SIZE_SET(nfp->a.attrs, fsize-size); + nfp->a.tag = NULL; + ARENA_TYPE_SET(fp->a.attrs, ARENA_TYPE_USED); + ARENA_SIZE_SET(fp->a.attrs, size); + fp->a.tag = __global_tag; + + /* Insert into all-block chain */ + nfp->a.prev = fp; + nfp->a.next = na; + na->a.prev = nfp; + fp->a.next = nfp; + + /* Replace current block on free chain */ + nfp->next_free = fp->next_free; + nfp->prev_free = fp->prev_free; + fp->next_free->prev_free = nfp; + fp->prev_free->next_free = nfp; } else { - /* Allocate the whole block */ - fp->a.type = ARENA_TYPE_USED; + /* Allocate the whole block */ + ARENA_TYPE_SET(fp->a.attrs, ARENA_TYPE_USED); + fp->a.tag = __global_tag; - /* Remove from free chain */ - fp->next_free->prev_free = fp->prev_free; - fp->prev_free->next_free = fp->next_free; + /* Remove from free chain */ + fp->next_free->prev_free = fp->prev_free; + fp->prev_free->next_free = fp->next_free; } return (void *)(&fp->a + 1); @@ -143,14 +155,113 @@ void *malloc(size_t size) /* Add the obligatory arena header, and round up */ size = (size + 2 * sizeof(struct arena_header) - 1) & ARENA_SIZE_MASK; - for (fp = __malloc_head.next_free; fp->a.type != ARENA_TYPE_HEAD; - fp = fp->next_free) { - if (fp->a.size >= size) { - /* Found fit -- allocate out of this block */ - return __malloc_from_block(fp, size); - } + for ( fp = __malloc_head.next_free ; ARENA_TYPE_GET(fp->a.attrs) != ARENA_TYPE_HEAD ; + fp = fp->next_free ) { + if ( ARENA_SIZE_GET(fp->a.attrs) >= size ) { + /* Found fit -- allocate out of this block */ + return __malloc_from_block(fp, size); + } } /* Nothing found... need to request a block from the kernel */ return NULL; /* No kernel to get stuff from */ } + +int posix_memalign(void **memptr, size_t alignment, size_t size) { + struct free_arena_header *fp, *nfp; + uintptr_t align_mask, align_addr; + + if (size == 0 || memptr == NULL) { + return EINVAL; + } + + if ((alignment & (alignment - 1)) != 0) + return EINVAL; + + // POSIX says to refuse alignments smaller than sizeof(void*) + if (alignment % sizeof(void*) != 0) + return EINVAL; + + // The arena allocator can't handle alignments smaller than this + if (alignment < sizeof(struct arena_header)) { + alignment = sizeof(struct arena_header); + } + align_mask = ~(uintptr_t)(alignment - 1); + + // Round up + size = (size + sizeof(struct arena_header) - 1) & ARENA_SIZE_MASK; + + *memptr = NULL; + + for (fp = __malloc_head.next_free; ARENA_TYPE_GET(fp->a.attrs) != ARENA_TYPE_HEAD; + fp = fp->next_free) { + + if (ARENA_SIZE_GET(fp->a.attrs) <= size) + continue; + + align_addr = (uintptr_t)fp; + + // Ensure the alignment leaves some space before for the header + if (align_addr % alignment == 0) { + align_addr += alignment; + } else { + align_addr = (align_addr + alignment - 1) & align_mask; + } + if (align_addr - (uintptr_t)fp == 2*sizeof(struct arena_header)) + align_addr += alignment; + + // See if now we have enough space + if (align_addr + size > (uintptr_t)fp + ARENA_SIZE_GET(fp->a.attrs)) + continue; + + // We have a winner... + if (align_addr - (uintptr_t)fp > sizeof(struct arena_header)) { + // We must split the block before the alignment point + nfp = (struct free_arena_header*)(align_addr - sizeof(struct arena_header)); + ARENA_TYPE_SET(nfp->a.attrs, ARENA_TYPE_FREE); + ARENA_SIZE_SET(nfp->a.attrs, + ARENA_SIZE_GET(fp->a.attrs) - ((uintptr_t)nfp - (uintptr_t)fp)); + nfp->a.tag = NULL; + nfp->a.prev = fp; + nfp->a.next = fp->a.next; + nfp->prev_free = fp; + nfp->next_free = fp->next_free; + + nfp->a.next->a.prev = nfp; + nfp->next_free->prev_free = nfp; + + ARENA_SIZE_SET(fp->a.attrs, (uintptr_t)nfp - (uintptr_t)fp); + + fp->a.next = nfp; + fp->next_free = nfp; + + *memptr = __malloc_from_block(nfp, size + sizeof(struct arena_header)); + } else { + *memptr = __malloc_from_block(fp, size + sizeof(struct arena_header)); + } + break; + } + + if (*memptr == NULL) + return ENOMEM; + + return 0; +} + +void *__mem_get_tag_global() { + return __global_tag; +} + +void __mem_set_tag_global(void *tag) { + __global_tag = tag; +} + +void *__mem_get_tag(void *memptr) { + struct arena_header *ah = (struct arena_header*)memptr - 1; + return ah->tag; +} + +void __mem_set_tag(void *memptr, void *tag) { + struct arena_header *ah = (struct arena_header*)memptr - 1; + ah->tag = tag; +} diff --git a/com32/lib/malloc.h b/com32/lib/malloc.h index bf754326..9665d83d 100644 --- a/com32/lib/malloc.h +++ b/com32/lib/malloc.h @@ -14,34 +14,41 @@ #define MALLOC_CHUNK_SIZE 65536 #define MALLOC_CHUNK_MASK (MALLOC_CHUNK_SIZE-1) + +struct free_arena_header; + /* * This structure should be a power of two. This becomes the * alignment unit. */ -struct free_arena_header; - struct arena_header { - size_t type; - size_t size; /* Also gives the location of the next entry */ + void *tag; + size_t attrs; /* Bits 0..1: Type, 2..3: Unused, 4..31: MSB of the size */ struct free_arena_header *next, *prev; }; + +#define ARENA_TYPE_USED 0x0 +#define ARENA_TYPE_FREE 0x1 +#define ARENA_TYPE_HEAD 0x2 #ifdef DEBUG_MALLOC -#define ARENA_TYPE_USED 0x64e69c70 -#define ARENA_TYPE_FREE 0x012d610a -#define ARENA_TYPE_HEAD 0x971676b5 -#define ARENA_TYPE_DEAD 0xeeeeeeee -#else -#define ARENA_TYPE_USED 0 -#define ARENA_TYPE_FREE 1 -#define ARENA_TYPE_HEAD 2 +#define ARENA_TYPE_DEAD 0x3 #endif #define ARENA_SIZE_MASK (~(uintptr_t)(sizeof(struct arena_header)-1)) +#define ARENA_TYPE_MASK ((size_t)0x3) #define ARENA_ALIGN_UP(p) ((char *)(((uintptr_t)(p) + ~ARENA_SIZE_MASK) & ARENA_SIZE_MASK)) #define ARENA_ALIGN_DOWN(p) ((char *)((uintptr_t)(p) & ARENA_SIZE_MASK)) +#define ARENA_SIZE_GET(attrs) ((attrs) & ARENA_SIZE_MASK) +#define ARENA_TYPE_GET(attrs) ((attrs) & ARENA_TYPE_MASK) + +#define ARENA_SIZE_SET(attrs, size) \ + ((attrs) = ((size) & ARENA_SIZE_MASK) | ((attrs) & ~ARENA_SIZE_MASK)) +#define ARENA_TYPE_SET(attrs, type) \ + ((attrs) = ((attrs) & ~ARENA_TYPE_MASK) | ((type) & ARENA_TYPE_MASK)) + /* * This structure should be no more than twice the size of the * previous structure. diff --git a/com32/lib/realloc.c b/com32/lib/realloc.c index 2969e313..64fff72b 100644 --- a/com32/lib/realloc.c +++ b/com32/lib/realloc.c @@ -26,7 +26,7 @@ void *realloc(void *ptr, size_t size) ((struct arena_header *)ptr - 1); /* Actual size of the old block */ - oldsize = ah->a.size; + oldsize = ARENA_SIZE_GET(ah->a.attrs); /* Add the obligatory arena header, and round up */ newsize = (size + 2 * sizeof(struct arena_header) - 1) & ARENA_SIZE_MASK; @@ -38,26 +38,28 @@ void *realloc(void *ptr, size_t size) } else { xsize = oldsize; - nah = ah->a.next; - if ((char *)nah == (char *)ah + ah->a.size && - nah->a.type == ARENA_TYPE_FREE && - oldsize + nah->a.size >= newsize) { - /* Merge in subsequent free block */ - ah->a.next = nah->a.next; - ah->a.next->a.prev = ah; - nah->next_free->prev_free = nah->prev_free; - nah->prev_free->next_free = nah->next_free; - xsize = (ah->a.size += nah->a.size); - } + nah = ah->a.next; + if ((char *)nah == (char *)ah + ARENA_SIZE_GET(ah->a.attrs) && + ARENA_TYPE_GET(nah->a.attrs) == ARENA_TYPE_FREE && + oldsize + ARENA_SIZE_GET(nah->a.attrs) >= newsize) { + /* Merge in subsequent free block */ + ah->a.next = nah->a.next; + ah->a.next->a.prev = ah; + nah->next_free->prev_free = nah->prev_free; + nah->prev_free->next_free = nah->next_free; + xsize = (ARENA_SIZE_SET(ah->a.attrs, ARENA_SIZE_GET(ah->a.attrs) + + ARENA_SIZE_GET(nah->a.attrs))); + } - if (xsize >= newsize) { - /* We can reallocate in place */ - if (xsize >= newsize + 2 * sizeof(struct arena_header)) { - /* Residual free block at end */ - nah = (struct free_arena_header *)((char *)ah + newsize); - nah->a.type = ARENA_TYPE_FREE; - nah->a.size = xsize - newsize; - ah->a.size = newsize; + if (xsize >= newsize) { + /* We can reallocate in place */ + if (xsize >= newsize + 2*sizeof(struct arena_header)) { + /* Residual free block at end */ + nah = (struct free_arena_header *)((char *)ah + newsize); + ARENA_TYPE_SET(nah->a.attrs, ARENA_TYPE_FREE); + ARENA_SIZE_SET(nah->a.attrs, xsize - newsize); + nah->a.tag = NULL; + ARENA_SIZE_SET(ah->a.attrs, newsize); /* Insert into block list */ nah->a.next = ah->a.next; @@ -81,18 +83,20 @@ void *realloc(void *ptr, size_t size) __malloc_head.next_free = nah; nah->next_free->prev_free = nah; } - } - /* otherwise, use up the whole block */ - return ptr; - } else { - /* Last resort: need to allocate a new block and copy */ - oldsize -= sizeof(struct arena_header); - newptr = malloc(size); - if (newptr) { - memcpy(newptr, ptr, min(size, oldsize)); - free(ptr); - } - return newptr; - } + } + /* otherwise, use up the whole block */ + return ptr; + } else { + /* Last resort: need to allocate a new block and copy */ + oldsize -= sizeof(struct arena_header); + newptr = malloc(size); + if (newptr) { + memcpy(newptr, ptr, min(size,oldsize)); + /* Retain tag from the old block */ + __mem_set_tag(newptr, __mem_get_tag(ptr)); + free(ptr); + } + return newptr; + } } } diff --git a/com32/lib/stack.c b/com32/lib/stack.c index dd7d9d46..f1c9ea2b 100644 --- a/com32/lib/stack.c +++ b/com32/lib/stack.c @@ -1,4 +1,4 @@ #include <stdlib.h> /* Default stack size 8 MB */ -size_t __stack_size = 8 << 20; +size_t __weak __stack_size = 8 << 20; diff --git a/com32/lib/sys/module/common.c b/com32/lib/sys/module/common.c new file mode 100644 index 00000000..01cbe692 --- /dev/null +++ b/com32/lib/sys/module/common.c @@ -0,0 +1,503 @@ +/* + * common.c + * + * Created on: Aug 11, 2008 + * Author: Stefan Bucur <stefanb@zytor.com> + */ + +#include <stdio.h> +#include <elf.h> +#include <string.h> + +#include <linux/list.h> +#include <sys/module.h> + +#include "elfutils.h" +#include "common.h" + +/** + * The one and only list of loaded modules + */ +LIST_HEAD(modules_head); + +// User-space debugging routines +#ifdef ELF_DEBUG +void print_elf_ehdr(Elf32_Ehdr *ehdr) { + int i; + + fprintf(stderr, "Identification:\t"); + for (i=0; i < EI_NIDENT; i++) { + printf("%d ", ehdr->e_ident[i]); + } + fprintf(stderr, "\n"); + fprintf(stderr, "Type:\t\t%u\n", ehdr->e_type); + fprintf(stderr, "Machine:\t%u\n", ehdr->e_machine); + fprintf(stderr, "Version:\t%u\n", ehdr->e_version); + fprintf(stderr, "Entry:\t\t0x%08x\n", ehdr->e_entry); + fprintf(stderr, "PHT Offset:\t0x%08x\n", ehdr->e_phoff); + fprintf(stderr, "SHT Offset:\t0x%08x\n", ehdr->e_shoff); + fprintf(stderr, "Flags:\t\t%u\n", ehdr->e_flags); + fprintf(stderr, "Header size:\t%u (Structure size: %u)\n", ehdr->e_ehsize, + sizeof(Elf32_Ehdr)); +} + +void print_elf_symbols(struct elf_module *module) { + unsigned int i; + Elf32_Sym *crt_sym; + + for (i = 1; i < module->symtable_size; i++) { + crt_sym = (Elf32_Sym*)(module->sym_table + i*module->syment_size); + + fprintf(stderr, "%s\n", module->str_table + crt_sym->st_name); + + } +} +#endif //ELF_DEBUG + + +/* + * Image files manipulation routines + */ + +int image_load(struct elf_module *module) { + module->_file = fopen(module->name, "rb"); + + if (module->_file == NULL) { + DBG_PRINT("Could not open object file '%s'\n", module->name); + goto error; + } + + module->_cr_offset = 0; + + return 0; + +error: + if (module->_file != NULL) { + fclose(module->_file); + module->_file = NULL; + } + + return -1; +} + + +int image_unload(struct elf_module *module) { + if (module->_file != NULL) { + fclose(module->_file); + module->_file = NULL; + } + module->_cr_offset = 0; + + return 0; +} + +int image_read(void *buff, size_t size, struct elf_module *module) { + size_t result = fread(buff, size, 1, module->_file); + + if (result < 1) + return -1; + + module->_cr_offset += size; + return 0; +} + +int image_skip(size_t size, struct elf_module *module) { + void *skip_buff = NULL; + size_t result; + + if (size == 0) + return 0; + + skip_buff = malloc(size); + result = fread(skip_buff, size, 1, module->_file); + free(skip_buff); + + if (result < 1) + return -1; + + module->_cr_offset += size; + return 0; +} + +int image_seek(Elf32_Off offset, struct elf_module *module) { + if (offset < module->_cr_offset) // Cannot seek backwards + return -1; + + return image_skip(offset - module->_cr_offset, module); +} + + +// Initialization of the module subsystem +int modules_init(void) { + return 0; +} + +// Termination of the module subsystem +void modules_term(void) { + +} + +// Allocates the structure for a new module +struct elf_module *module_alloc(const char *name) { + struct elf_module *result = malloc(sizeof(struct elf_module)); + + memset(result, 0, sizeof(struct elf_module)); + + INIT_LIST_HEAD(&result->list); + INIT_LIST_HEAD(&result->required); + INIT_LIST_HEAD(&result->dependants); + + strncpy(result->name, name, MODULE_NAME_SIZE); + + return result; +} + +struct module_dep *module_dep_alloc(struct elf_module *module) { + struct module_dep *result = malloc(sizeof(struct module_dep)); + + INIT_LIST_HEAD (&result->list); + + result->module = module; + + return result; +} + +struct elf_module *module_find(const char *name) { + struct elf_module *cr_module; + + for_each_module(cr_module) { + if (strcmp(cr_module->name, name) == 0) + return cr_module; + } + + return NULL; +} + + +// Performs verifications on ELF header to assure that the open file is a +// valid SYSLINUX ELF module. +int check_header_common(Elf32_Ehdr *elf_hdr) { + // Check the header magic + if (elf_hdr->e_ident[EI_MAG0] != ELFMAG0 || + elf_hdr->e_ident[EI_MAG1] != ELFMAG1 || + elf_hdr->e_ident[EI_MAG2] != ELFMAG2 || + elf_hdr->e_ident[EI_MAG3] != ELFMAG3) { + + DBG_PRINT("The file is not an ELF object\n"); + return -1; + } + + if (elf_hdr->e_ident[EI_CLASS] != MODULE_ELF_CLASS) { + DBG_PRINT("Invalid ELF class code\n"); + return -1; + } + + if (elf_hdr->e_ident[EI_DATA] != MODULE_ELF_DATA) { + DBG_PRINT("Invalid ELF data encoding\n"); + return -1; + } + + if (elf_hdr->e_ident[EI_VERSION] != MODULE_ELF_VERSION || + elf_hdr->e_version != MODULE_ELF_VERSION) { + DBG_PRINT("Invalid ELF file version\n"); + return -1; + } + + if (elf_hdr->e_machine != MODULE_ELF_MACHINE) { + DBG_PRINT("Invalid ELF architecture\n"); + return -1; + } + + return 0; +} + + +int enforce_dependency(struct elf_module *req, struct elf_module *dep) { + struct module_dep *crt_dep; + struct module_dep *new_dep; + + list_for_each_entry(crt_dep, &req->dependants, list) { + if (crt_dep->module == dep) { + // The dependency is already enforced + return 0; + } + } + + new_dep = module_dep_alloc(req); + list_add(&new_dep->list, &dep->required); + + new_dep = module_dep_alloc(dep); + list_add(&new_dep->list, &req->dependants); + + return 0; +} + +int clear_dependency(struct elf_module *req, struct elf_module *dep) { + struct module_dep *crt_dep = NULL; + int found = 0; + + list_for_each_entry(crt_dep, &req->dependants, list) { + if (crt_dep->module == dep) { + found = 1; + break; + } + } + + if (found) { + list_del(&crt_dep->list); + free(crt_dep); + } + + found = 0; + + list_for_each_entry(crt_dep, &dep->required, list) { + if (crt_dep->module == req) { + found = 1; + break; + } + } + + if (found) { + list_del(&crt_dep->list); + free(crt_dep); + } + + return 0; +} + +int check_symbols(struct elf_module *module) { + unsigned int i; + Elf32_Sym *crt_sym = NULL, *ref_sym = NULL; + char *crt_name; + struct elf_module *crt_module; + + int strong_count; + int weak_count; + + for (i = 1; i < module->symtable_size; i++) { + crt_sym = (Elf32_Sym*)(module->sym_table + i * module->syment_size); + crt_name = module->str_table + crt_sym->st_name; + + strong_count = 0; + weak_count = 0; + + for_each_module(crt_module) { + ref_sym = module_find_symbol(crt_name, crt_module); + + // If we found a definition for our symbol... + if (ref_sym != NULL && ref_sym->st_shndx != SHN_UNDEF) { + switch (ELF32_ST_BIND(ref_sym->st_info)) { + case STB_GLOBAL: + strong_count++; + break; + case STB_WEAK: + weak_count++; + break; + } + } + } + + if (crt_sym->st_shndx == SHN_UNDEF) { + // We have an undefined symbol + if (strong_count == 0 && weak_count == 0) { + DBG_PRINT("Symbol %s is undefined\n", crt_name); + return -1; + } + } else { + if (strong_count > 0 && ELF32_ST_BIND(ref_sym->st_info) == STB_GLOBAL) { + // It's not an error - at relocation, the most recent symbol + // will be considered + DBG_PRINT("Info: Symbol %s is defined more than once\n", crt_name); + } + } + } + + return 0; +} + +int module_unloadable(struct elf_module *module) { + if (!list_empty(&module->dependants)) + return 0; + + return 1; +} + + +// Unloads the module from the system and releases all the associated memory +int module_unload(struct elf_module *module) { + struct module_dep *crt_dep, *tmp; + // Make sure nobody needs us + if (!module_unloadable(module)) { + DBG_PRINT("Module is required by other modules.\n"); + return -1; + } + + // Remove any dependency information + list_for_each_entry_safe(crt_dep, tmp, &module->required, list) { + clear_dependency(crt_dep->module, module); + } + + // Remove the module from the module list + list_del_init(&module->list); + + // Release the loaded segments or sections + if (module->module_addr != NULL) { + elf_free(module->module_addr); + + DBG_PRINT("%s MODULE %s UNLOADED\n", module->shallow ? "SHALLOW" : "", + module->name); + } + // Release the module structure + free(module); + + return 0; +} + + +static Elf32_Sym *module_find_symbol_sysv(const char *name, struct elf_module *module) { + unsigned long h = elf_hash((const unsigned char*)name); + Elf32_Word *cr_word = module->hash_table; + + Elf32_Word nbucket = *cr_word++; + cr_word++; // Skip nchain + + Elf32_Word *bkt = cr_word; + Elf32_Word *chn = cr_word + nbucket; + + Elf32_Word crt_index = bkt[h % module->hash_table[0]]; + Elf32_Sym *crt_sym; + + + while (crt_index != STN_UNDEF) { + crt_sym = (Elf32_Sym*)(module->sym_table + crt_index*module->syment_size); + + if (strcmp(name, module->str_table + crt_sym->st_name) == 0) + return crt_sym; + + crt_index = chn[crt_index]; + } + + return NULL; +} + +static Elf32_Sym *module_find_symbol_gnu(const char *name, struct elf_module *module) { + unsigned long h = elf_gnu_hash((const unsigned char*)name); + + // Setup code (TODO: Optimize this by computing only once) + Elf32_Word *cr_word = module->ghash_table; + Elf32_Word nbucket = *cr_word++; + Elf32_Word symbias = *cr_word++; + Elf32_Word bitmask_nwords = *cr_word++; + + if ((bitmask_nwords & (bitmask_nwords - 1)) != 0) { + DBG_PRINT("Invalid GNU Hash structure\n"); + return NULL; + } + + Elf32_Word gnu_shift = *cr_word++; + + Elf32_Addr *gnu_bitmask = (Elf32_Addr*)cr_word; + cr_word += MODULE_ELF_CLASS_SIZE / 32 * bitmask_nwords; + + Elf32_Word *gnu_buckets = cr_word; + cr_word += nbucket; + + Elf32_Word *gnu_chain_zero = cr_word - symbias; + + // Computations + Elf32_Word bitmask_word = gnu_bitmask[(h / MODULE_ELF_CLASS_SIZE) & + (bitmask_nwords - 1)]; + + unsigned int hashbit1 = h & (MODULE_ELF_CLASS_SIZE - 1); + unsigned int hashbit2 = (h >> gnu_shift) & (MODULE_ELF_CLASS_SIZE - 1); + + if ((bitmask_word >> hashbit1) & (bitmask_word >> hashbit2) & 1) { + unsigned long rem; + Elf32_Word bucket; + + rem = h % nbucket; + + bucket = gnu_buckets[rem]; + + if (bucket != 0) { + const Elf32_Word* hasharr = &gnu_chain_zero[bucket]; + + do { + if (((*hasharr ^ h ) >> 1) == 0) { + Elf32_Sym *crt_sym = (Elf32_Sym*)(module->sym_table + + (hasharr - gnu_chain_zero) * module->syment_size); + + if (strcmp(name, module->str_table + crt_sym->st_name) == 0) { + return crt_sym; + } + } + } while ((*hasharr++ & 1u) == 0); + } + } + + return NULL; +} + +static Elf32_Sym *module_find_symbol_iterate(const char *name, + struct elf_module *module) { + + unsigned int i; + Elf32_Sym *crt_sym; + + for (i=1; i < module->symtable_size; i++) { + crt_sym = (Elf32_Sym*)(module->sym_table + i*module->syment_size); + + if (strcmp(name, module->str_table + crt_sym->st_name) == 0) { + return crt_sym; + } + } + + return NULL; +} + +Elf32_Sym *module_find_symbol(const char *name, struct elf_module *module) { + Elf32_Sym *result = NULL; + + if (module->ghash_table != NULL) + result = module_find_symbol_gnu(name, module); + + if (result == NULL) { + if (module->hash_table != NULL) + result = module_find_symbol_sysv(name, module); + else + result = module_find_symbol_iterate(name, module); + } + + return result; +} + +Elf32_Sym *global_find_symbol(const char *name, struct elf_module **module) { + struct elf_module *crt_module; + Elf32_Sym *crt_sym = NULL; + Elf32_Sym *result = NULL; + + for_each_module(crt_module) { + crt_sym = module_find_symbol(name, crt_module); + + if (crt_sym != NULL && crt_sym->st_shndx != SHN_UNDEF) { + switch (ELF32_ST_BIND(crt_sym->st_info)) { + case STB_GLOBAL: + if (module != NULL) { + *module = crt_module; + } + return crt_sym; + case STB_WEAK: + // Consider only the first weak symbol + if (result == NULL) { + if (module != NULL) { + *module = crt_module; + } + result = crt_sym; + } + break; + } + } + } + + return result; +} diff --git a/com32/lib/sys/module/common.h b/com32/lib/sys/module/common.h new file mode 100644 index 00000000..bcbffdf1 --- /dev/null +++ b/com32/lib/sys/module/common.h @@ -0,0 +1,65 @@ +/* + * common.h - Common internal operations performed by the module subsystem + * + * Created on: Aug 11, 2008 + * Author: Stefan Bucur <stefanb@zytor.com> + */ + +#ifndef COMMON_H_ +#define COMMON_H_ + +#include <stdio.h> + +#include <sys/module.h> +#include <linux/list.h> + +#include "elfutils.h" + + +// Performs an operation and jumps to a given label if an error occurs +#define CHECKED(res, expr, error) \ + do { \ + (res) = (expr); \ + if ((res) < 0) \ + goto error; \ + } while (0) + +#define MIN(x,y) (((x) < (y)) ? (x) : (y)) +#define MAX(x,y) (((x) > (y)) ? (x) : (y)) + + +#ifdef ELF_DEBUG +#define DBG_PRINT(fmt, args...) fprintf(stderr, "[ELF] " fmt, ##args) +#else +#define DBG_PRINT(fmt, args...) // Expand to nothing +#endif + +// User-space debugging routines +#ifdef ELF_DEBUG + +extern void print_elf_ehdr(Elf32_Ehdr *ehdr); +extern void print_elf_symbols(struct elf_module *module); + +#endif //ELF_DEBUG + +/* + * Image files manipulation routines + */ + +extern int image_load(struct elf_module *module); +extern int image_unload(struct elf_module *module); +extern int image_read(void *buff, size_t size, struct elf_module *module); +extern int image_skip(size_t size, struct elf_module *module); +extern int image_seek(Elf32_Off offset, struct elf_module *module); + +extern struct module_dep *module_dep_alloc(struct elf_module *module); + +extern int check_header_common(Elf32_Ehdr *elf_hdr); + +extern int enforce_dependency(struct elf_module *req, struct elf_module *dep); +extern int clear_dependency(struct elf_module *req, struct elf_module *dep); + +extern int check_symbols(struct elf_module *module); + + +#endif /* COMMON_H_ */ diff --git a/com32/lib/sys/module/elf_module.c b/com32/lib/sys/module/elf_module.c new file mode 100644 index 00000000..4b1f2bbd --- /dev/null +++ b/com32/lib/sys/module/elf_module.c @@ -0,0 +1,488 @@ +/* + * elf_module.c + * + * Created on: Aug 11, 2008 + * Author: Stefan Bucur <stefanb@zytor.com> + */ + + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <elf.h> + +#include <linux/list.h> +#include <sys/module.h> + +#include "elfutils.h" +#include "common.h" + + +static int check_header(Elf32_Ehdr *elf_hdr) { + int res; + + res = check_header_common(elf_hdr); + + if (res != 0) + return res; + + if (elf_hdr->e_type != MODULE_ELF_TYPE) { + DBG_PRINT("The ELF file must be a shared object\n"); + return -1; + } + + if (elf_hdr->e_phoff == 0x00000000) { + DBG_PRINT("PHT missing\n"); + return -1; + } + + return 0; +} + +/* + * + * The implementation assumes that the loadable segments are present + * in the PHT sorted by their offsets, so that only forward seeks would + * be necessary. + */ +static int load_segments(struct elf_module *module, Elf32_Ehdr *elf_hdr) { + int i; + int res = 0; + void *pht = NULL; + Elf32_Phdr *cr_pht; + + Elf32_Addr min_addr = 0x00000000; // Min. ELF vaddr + Elf32_Addr max_addr = 0x00000000; // Max. ELF vaddr + Elf32_Word max_align = sizeof(void*); // Min. align of posix_memalign() + Elf32_Addr min_alloc, max_alloc; // Min. and max. aligned allocables + + Elf32_Addr dyn_addr = 0x00000000; + + // Get to the PHT + image_seek(elf_hdr->e_phoff, module); + + // Load the PHT + pht = malloc(elf_hdr->e_phnum * elf_hdr->e_phentsize); + image_read(pht, elf_hdr->e_phnum * elf_hdr->e_phentsize, module); + + // Compute the memory needings of the module + for (i=0; i < elf_hdr->e_phnum; i++) { + cr_pht = (Elf32_Phdr*)(pht + i * elf_hdr->e_phentsize); + + switch (cr_pht->p_type) { + case PT_LOAD: + if (i == 0) { + min_addr = cr_pht->p_vaddr; + } else { + min_addr = MIN(min_addr, cr_pht->p_vaddr); + } + + max_addr = MAX(max_addr, cr_pht->p_vaddr + cr_pht->p_memsz); + max_align = MAX(max_align, cr_pht->p_align); + break; + case PT_DYNAMIC: + dyn_addr = cr_pht->p_vaddr; + break; + default: + // Unsupported - ignore + break; + } + } + + if (max_addr - min_addr == 0) { + // No loadable segments + DBG_PRINT("No loadable segments found\n"); + goto out; + } + + if (dyn_addr == 0) { + DBG_PRINT("No dynamic information segment found\n"); + goto out; + } + + // The minimum address that should be allocated + min_alloc = min_addr - (min_addr % max_align); + + // The maximum address that should be allocated + max_alloc = max_addr - (max_addr % max_align); + if (max_addr % max_align > 0) + max_alloc += max_align; + + + if (elf_malloc(&module->module_addr, + max_align, + max_alloc-min_alloc) != 0) { + + DBG_PRINT("Could not allocate segments\n"); + goto out; + } + + module->base_addr = (Elf32_Addr)(module->module_addr) - min_alloc; + module->module_size = max_alloc - min_alloc; + + // Zero-initialize the memory + memset(module->module_addr, 0, module->module_size); + + for (i = 0; i < elf_hdr->e_phnum; i++) { + cr_pht = (Elf32_Phdr*)(pht + i * elf_hdr->e_phentsize); + + if (cr_pht->p_type == PT_LOAD) { + // Copy the segment at its destination + if (cr_pht->p_offset < module->_cr_offset) { + // The segment contains data before the current offset + // It can be discarded without worry - it would contain only + // headers + Elf32_Off aux_off = module->_cr_offset - cr_pht->p_offset; + + if (image_read(module_get_absolute(cr_pht->p_vaddr, module) + aux_off, + cr_pht->p_filesz - aux_off, module) < 0) { + res = -1; + goto out; + } + } else { + if (image_seek(cr_pht->p_offset, module) < 0) { + res = -1; + goto out; + } + + if (image_read(module_get_absolute(cr_pht->p_vaddr, module), + cr_pht->p_filesz, module) < 0) { + res = -1; + goto out; + } + } + + DBG_PRINT("Loadable segment of size 0x%08x copied from vaddr 0x%08x at 0x%08x\n", + cr_pht->p_filesz, + cr_pht->p_vaddr, + (Elf32_Addr)module_get_absolute(cr_pht->p_vaddr, module)); + } + } + + // Setup dynamic segment location + module->dyn_table = module_get_absolute(dyn_addr, module); + + DBG_PRINT("Base address: 0x%08x, aligned at 0x%08x\n", module->base_addr, + max_align); + DBG_PRINT("Module size: 0x%08x\n", module->module_size); + +out: + // Free up allocated memory + if (pht != NULL) + free(pht); + + return res; +} + + +static int prepare_dynlinking(struct elf_module *module) { + Elf32_Dyn *dyn_entry = module->dyn_table; + + while (dyn_entry->d_tag != DT_NULL) { + switch (dyn_entry->d_tag) { + case DT_NEEDED: + // TODO: Manage dependencies here + break; + case DT_HASH: + module->hash_table = + (Elf32_Word*)module_get_absolute(dyn_entry->d_un.d_ptr, module); + break; + case DT_GNU_HASH: + module->ghash_table = + (Elf32_Word*)module_get_absolute(dyn_entry->d_un.d_ptr, module); + break; + case DT_STRTAB: + module->str_table = + (char*)module_get_absolute(dyn_entry->d_un.d_ptr, module); + break; + case DT_SYMTAB: + module->sym_table = + module_get_absolute(dyn_entry->d_un.d_ptr, module); + break; + case DT_STRSZ: + module->strtable_size = dyn_entry->d_un.d_val; + break; + case DT_SYMENT: + module->syment_size = dyn_entry->d_un.d_val; + break; + case DT_PLTGOT: // The first entry in the GOT + module->got = module_get_absolute(dyn_entry->d_un.d_ptr, module); + break; + } + + dyn_entry++; + } + + // Now compute the number of symbols in the symbol table + if (module->ghash_table != NULL) { + module->symtable_size = module->ghash_table[1]; + } else { + module->symtable_size = module->hash_table[1]; + } + + return 0; +} + + +static int perform_relocation(struct elf_module *module, Elf32_Rel *rel) { + Elf32_Word *dest = module_get_absolute(rel->r_offset, module); + + // The symbol reference index + Elf32_Word sym = ELF32_R_SYM(rel->r_info); + unsigned char type = ELF32_R_TYPE(rel->r_info); + + // The symbol definition (if applicable) + Elf32_Sym *sym_def = NULL; + struct elf_module *sym_module = NULL; + Elf32_Addr sym_addr = 0x0; + + if (sym > 0) { + // Find out details about the symbol + + // The symbol reference + Elf32_Sym *sym_ref = + (Elf32_Sym*)(module->sym_table + sym * module->syment_size); + + // The symbol definition + sym_def = + global_find_symbol(module->str_table + sym_ref->st_name, + &sym_module); + + if (sym_def == NULL) { + // This should never happen + DBG_PRINT("Cannot perform relocation for symbol %s\n", + module->str_table + sym_ref->st_name); + + return -1; + } + + // Compute the absolute symbol virtual address + sym_addr = (Elf32_Addr)module_get_absolute(sym_def->st_value, sym_module); + + if (sym_module != module) { + // Create a dependency + enforce_dependency(sym_module, module); + } + } + + switch (type) { + case R_386_NONE: + // Do nothing + break; + case R_386_32: + *dest += sym_addr; + break; + case R_386_PC32: + *dest += sym_addr - (Elf32_Addr)dest; + break; + case R_386_COPY: + if (sym_addr > 0) { + memcpy((void*)dest, (void*)sym_addr, sym_def->st_size); + } + break; + case R_386_GLOB_DAT: + case R_386_JMP_SLOT: + // Maybe TODO: Keep track of the GOT entries allocations + *dest = sym_addr; + break; + case R_386_RELATIVE: + *dest += module->base_addr; + break; + default: + DBG_PRINT("Relocation type %d not supported\n", type); + return -1; + } + + return 0; +} + +static int resolve_symbols(struct elf_module *module) { + Elf32_Dyn *dyn_entry = module->dyn_table; + unsigned int i; + int res; + + Elf32_Word plt_rel_size = 0; + void *plt_rel = NULL; + + void *rel = NULL; + Elf32_Word rel_size = 0; + Elf32_Word rel_entry = 0; + + // The current relocation + Elf32_Rel *crt_rel; + + while (dyn_entry->d_tag != DT_NULL) { + switch(dyn_entry->d_tag) { + + // PLT relocation information + case DT_PLTRELSZ: + plt_rel_size = dyn_entry->d_un.d_val; + break; + case DT_PLTREL: + if (dyn_entry->d_un.d_val != DT_REL) { + DBG_PRINT("Unsupported PLT relocation\n"); + return -1; + } + case DT_JMPREL: + plt_rel = module_get_absolute(dyn_entry->d_un.d_ptr, module); + break; + + // Standard relocation information + case DT_REL: + rel = module_get_absolute(dyn_entry->d_un.d_ptr, module); + break; + case DT_RELSZ: + rel_size = dyn_entry->d_un.d_val; + break; + case DT_RELENT: + rel_entry = dyn_entry->d_un.d_val; + break; + + // Module initialization and termination + case DT_INIT: + // TODO Implement initialization functions + break; + case DT_FINI: + // TODO Implement finalization functions + break; + } + + dyn_entry++; + } + + if (rel_size > 0) { + // Process standard relocations + for (i = 0; i < rel_size/rel_entry; i++) { + crt_rel = (Elf32_Rel*)(rel + i*rel_entry); + + res = perform_relocation(module, crt_rel); + + if (res < 0) + return res; + } + + } + + if (plt_rel_size > 0) { + // TODO: Permit this lazily + // Process PLT relocations + for (i = 0; i < plt_rel_size/sizeof(Elf32_Rel); i++) { + crt_rel = (Elf32_Rel*)(plt_rel + i*sizeof(Elf32_Rel)); + + res = perform_relocation(module, crt_rel); + + if (res < 0) + return res; + } + } + + return 0; +} + + + +static int extract_operations(struct elf_module *module) { + Elf32_Sym *init_sym = module_find_symbol(MODULE_ELF_INIT_PTR, module); + Elf32_Sym *exit_sym = module_find_symbol(MODULE_ELF_EXIT_PTR, module); + Elf32_Sym *main_sym = module_find_symbol(MODULE_ELF_MAIN_PTR, module); + + if (init_sym == NULL) { + DBG_PRINT("Cannot find initialization routine pointer.\n"); + return -1; + } + if (exit_sym == NULL) { + DBG_PRINT("Cannot find exit routine pointer.\n"); + return -1; + } + if (main_sym == NULL) { + DBG_PRINT("Cannot find main routine pointer.\n"); + return -1; + } + + module->init_func = (module_init_t*)module_get_absolute( + init_sym->st_value, module); + if (*(module->init_func) == NULL) { + module->init_func = NULL; + } + + module->exit_func = (module_exit_t*)module_get_absolute( + exit_sym->st_value, module); + if (*(module->exit_func) == NULL) { + module->exit_func = NULL; + } + + module->main_func = (module_main_t*)module_get_absolute( + main_sym->st_value, module); + if (*(module->main_func) == NULL) { + module->main_func = NULL; + } + + return 0; +} + +// Loads the module into the system +int module_load(struct elf_module *module) { + int res; + Elf32_Ehdr elf_hdr; + + // Do not allow duplicate modules + if (module_find(module->name) != NULL) { + DBG_PRINT("Module already loaded.\n"); + return -1; + } + + // Get a mapping/copy of the ELF file in memory + res = image_load(module); + + if (res < 0) { + return res; + } + + // The module is a fully featured dynamic library + module->shallow = 0; + + CHECKED(res, image_read(&elf_hdr, sizeof(Elf32_Ehdr), module), error); + + // Checking the header signature and members + CHECKED(res, check_header(&elf_hdr), error); + + // Load the segments in the memory + CHECKED(res, load_segments(module, &elf_hdr), error); + // Obtain dynamic linking information + CHECKED(res, prepare_dynlinking(module), error); + + // Check the symbols for duplicates / missing definitions + CHECKED(res, check_symbols(module), error); + + // Obtain constructors and destructors + CHECKED(res, extract_operations(module), error); + + // Add the module at the beginning of the module list + list_add(&module->list, &modules_head); + + // Perform the relocations + resolve_symbols(module); + + + + // The file image is no longer needed + image_unload(module); + + DBG_PRINT("MODULE %s LOADED SUCCESSFULLY (init@0x%08X, exit@0x%08X)\n", + module->name, *(module->init_func), *(module->exit_func)); + + return 0; + +error: + // Remove the module from the module list (if applicable) + list_del_init(&module->list); + + if (module->module_addr != NULL) { + elf_free(module->module_addr); + module->module_addr = NULL; + } + + image_unload(module); + + return res; +} diff --git a/com32/lib/sys/module/elfutils.c b/com32/lib/sys/module/elfutils.c new file mode 100644 index 00000000..0e653171 --- /dev/null +++ b/com32/lib/sys/module/elfutils.c @@ -0,0 +1,89 @@ +#include <stdlib.h> +#include <errno.h> + +#include "elfutils.h" + +unsigned long elf_hash(const unsigned char *name) { + unsigned long h = 0; + unsigned long g; + + while (*name) { + h = (h << 4) + *name++; + if ((g = h & 0xF0000000)) + h ^= g >> 24; + + h &= ~g; + } + + return h; +} + +unsigned long elf_gnu_hash(const unsigned char *name) { + unsigned long h = 5381; + unsigned char c; + + for (c = *name; c != '\0'; c = *++name) { + h = h * 33 + c; + } + + return h & 0xFFFFFFFF; +} + +#ifdef ELF_NO_POSIX_MEMALIGN + +struct memalign_info { + void *start_addr; + char data[0]; +}; + +int elf_malloc(void **memptr, size_t alignment, size_t size) { + void *start_addr = NULL; + struct memalign_info *info; + + if ((alignment & (alignment - 1)) != 0) + return EINVAL; + if (alignment % sizeof(void*) != 0) + alignment = sizeof(void*); + + start_addr = malloc(size + (alignment > sizeof(struct memalign_info) ? + alignment : sizeof(struct memalign_info))); + + if (start_addr == NULL) + return ENOMEM; + + + info = (struct memalign_info*)(start_addr - + ((unsigned long)start_addr % alignment) + + alignment - sizeof(struct memalign_info)); + + info->start_addr = start_addr; + + *memptr = info->data; + + return 0; +} + +void elf_free(void *memptr) { + struct memalign_info *info = (struct memalign_info*)(memptr - + sizeof(struct memalign_info)); + + free(info->start_addr); +} + +#else + +int elf_malloc(void **memptr, size_t alignment, size_t size) { + if ((alignment & (alignment - 1)) != 0) + return EINVAL; + + if (alignment % sizeof(void*) != 0) + alignment = sizeof(void*); + + return posix_memalign(memptr, alignment, size); +} + +void elf_free(void *memptr) { + free(memptr); +} + +#endif //ELF_NO_POSIX_MEMALIGN diff --git a/com32/lib/sys/module/elfutils.h b/com32/lib/sys/module/elfutils.h new file mode 100644 index 00000000..b18968f3 --- /dev/null +++ b/com32/lib/sys/module/elfutils.h @@ -0,0 +1,64 @@ +#ifndef ELF_UTILS_H_ +#define ELF_UTILS_H_ + +#include <elf.h> +#include <stdlib.h> + +/** + * elf_get_header - Returns a pointer to the ELF header structure. + * @elf_image: pointer to the ELF file image in memory + */ +static inline Elf32_Ehdr *elf_get_header(void *elf_image) { + return (Elf32_Ehdr*)elf_image; +} + +/** + * elf_get_pht - Returns a pointer to the first entry in the PHT. + * @elf_image: pointer to the ELF file image in memory + */ +static inline Elf32_Phdr *elf_get_pht(void *elf_image) { + Elf32_Ehdr *elf_hdr = elf_get_header(elf_image); + + return (Elf32_Phdr*)((Elf32_Off)elf_hdr + elf_hdr->e_phoff); +} + +// +/** + * elf_get_ph - Returns the element with the given index in the PTH + * @elf_image: pointer to the ELF file image in memory + * @index: the index of the PHT entry to look for + */ +static inline Elf32_Phdr *elf_get_ph(void *elf_image, int index) { + Elf32_Phdr *elf_pht = elf_get_pht(elf_image); + Elf32_Ehdr *elf_hdr = elf_get_header(elf_image); + + return (Elf32_Phdr*)((Elf32_Off)elf_pht + index * elf_hdr->e_phentsize); +} + +/** + * elf_hash - Returns the index in a SysV hash table for the symbol name. + * @name: the name of the symbol to look for + */ +extern unsigned long elf_hash(const unsigned char *name); + +/** + * elf_gnu_hash - Returns the index in a GNU hash table for the symbol name. + * @name: the name of the symbol to look for + */ +extern unsigned long elf_gnu_hash(const unsigned char *name); + +/** + * elf_malloc - Allocates memory to be used by ELF module contents. + * @memptr: pointer to a variable to hold the address of the allocated block. + * @alignment: alignment constraints of the block + * @size: the required size of the block + */ +extern int elf_malloc(void **memptr, size_t alignment, size_t size); + +/** + * elf_free - Releases memory previously allocated by elf_malloc. + * @memptr: the address of the allocated block + */ +extern void elf_free(void *memptr); + +#endif /*ELF_UTILS_H_*/ diff --git a/com32/lib/sys/module/exec.c b/com32/lib/sys/module/exec.c new file mode 100644 index 00000000..3cd53187 --- /dev/null +++ b/com32/lib/sys/module/exec.c @@ -0,0 +1,174 @@ +/* + * exec.c + * + * Created on: Aug 14, 2008 + * Author: Stefan Bucur <stefanb@zytor.com> + */ + +#include <sys/module.h> +#include <sys/exec.h> +#include <stdio.h> +#include <string.h> +#include <stdarg.h> + + + +#define DBG_PRINT(fmt, args...) fprintf(stderr, "[EXEC] " fmt, ##args) + + +static struct elf_module *mod_root = NULL; + +static char *module_get_fullname(const char *name) { + static char name_buff[MODULE_NAME_SIZE]; + + if (name == NULL) + return NULL; + + strcpy(name_buff, EXEC_DIRECTORY); + strcat(name_buff, name); + + return name_buff; +} + +int exec_init() { + int res; + + res = modules_init(); + + if (res != 0) + return res; + + // Load the root module + mod_root = module_alloc(module_get_fullname(EXEC_ROOT_NAME)); + + if (mod_root == NULL) + return -1; + + res = module_load_shallow(mod_root); + + if (res != 0) { + mod_root = NULL; + return res; + } + + return 0; +} + +int load_library(const char *name) { + int res; + struct elf_module *module = module_alloc(module_get_fullname(name)); + + if (module == NULL) + return -1; + + res = module_load(module); + + + if (res != 0) { + module_unload(module); + return res; + } + + if (module->main_func != NULL) { + DBG_PRINT("Cannot load executable module as library.\n"); + module_unload(module); + return -1; + } + + if (module->init_func != NULL) { + res = (*(module->init_func))(); + DBG_PRINT("Initialization function returned: %d\n", res); + } else { + DBG_PRINT("No initialization function present.\n"); + } + + if (res != 0) { + module_unload(module); + return res; + } + + return 0; +} + +int unload_library(const char *name) { + int res; + struct elf_module *module = module_find(module_get_fullname(name)); + + if (module == NULL) + return -1; + + if (!module_unloadable(module)) { + return -1; + } + + if (module->exit_func != NULL) { + (*(module->exit_func))(); + } + + res = module_unload(module); + + return res; +} + +int spawnv(const char *name, const char **argv) { + int res, ret_val = 0; + + struct elf_module *module = module_alloc(module_get_fullname(name)); + + if (module == NULL) + return -1; + + res = module_load(module); + + if (res != 0) { + module_unload(module); + return res; + } + + if (module->main_func != NULL) { + const char **last_arg = argv; + void *old_tag; + while (*last_arg != NULL) + last_arg++; + + // Setup the memory allocation context + old_tag = __mem_get_tag_global(); + __mem_set_tag_global(module); + + // Execute the program + ret_val = (*(module->main_func))(last_arg - argv, argv); + + // Clean up the allocation context + __free_tagged(module); + // Restore the allocation context + __mem_set_tag_global(old_tag); + } else { + // We can't execute without a main function + module_unload(module); + return -1; + } + + res = module_unload(module); + + if (res != 0) { + return res; + } + + return ((unsigned int)ret_val & 0xFF); +} + +int spawnl(const char *name, const char *arg, ...) { + /* + * NOTE: We assume the standard ABI specification for the i386 + * architecture. This code may not work if used in other + * circumstances, including non-variadic functions, different + * architectures and calling conventions. + */ + + return spawnv(name, &arg); +} + + +void exec_term() { + modules_term(); +} diff --git a/com32/lib/sys/module/shallow_module.c b/com32/lib/sys/module/shallow_module.c new file mode 100644 index 00000000..f198c0db --- /dev/null +++ b/com32/lib/sys/module/shallow_module.c @@ -0,0 +1,160 @@ +/* + * shallow_module.c + * + * Created on: Aug 11, 2008 + * Author: Stefan Bucur <stefanb@zytor.com> + */ + + + +#include <sys/module.h> + +#include "common.h" +#include "elfutils.h" + + +static int check_header_shallow(Elf32_Ehdr *elf_hdr) { + int res; + + res = check_header_common(elf_hdr); + + if (res != 0) + return res; + + if (elf_hdr->e_shoff == 0x00000000) { + DBG_PRINT("SHT missing\n"); + return -1; + } + + return 0; +} + +static int load_shallow_sections(struct elf_module *module, Elf32_Ehdr *elf_hdr) { + int i; + int res = 0; + void *sht = NULL; + void *buffer = NULL; + Elf32_Shdr *crt_sht; + Elf32_Off buff_offset; + + Elf32_Off min_offset = 0xFFFFFFFF; + Elf32_Off max_offset = 0x00000000; + Elf32_Word max_align = 0x1; + + Elf32_Off sym_offset = 0xFFFFFFFF; + Elf32_Off str_offset = 0xFFFFFFFF; + + + char *sh_strtable; + + // We buffer the data up to the SHT + buff_offset = module->_cr_offset; + + buffer = malloc(elf_hdr->e_shoff - buff_offset); + // Get to the SHT + image_read(buffer, elf_hdr->e_shoff - buff_offset, module); + + // Load the SHT + sht = malloc(elf_hdr->e_shnum * elf_hdr->e_shentsize); + image_read(sht, elf_hdr->e_shnum * elf_hdr->e_shentsize, module); + + // Get the string table of the section names + crt_sht = (Elf32_Shdr*)(sht + elf_hdr->e_shstrndx * elf_hdr->e_shentsize); + sh_strtable = (char*)(buffer + (crt_sht->sh_offset - buff_offset)); + + for (i = 0; i < elf_hdr->e_shnum; i++) { + crt_sht = (Elf32_Shdr*)(sht + i*elf_hdr->e_shentsize); + + if (strcmp(".symtab", sh_strtable + crt_sht->sh_name) == 0) { + // We found the symbol table + min_offset = MIN(min_offset, crt_sht->sh_offset); + max_offset = MAX(max_offset, crt_sht->sh_offset + crt_sht->sh_size); + max_align = MAX(max_align, crt_sht->sh_addralign); + + sym_offset = crt_sht->sh_offset; + + module->syment_size = crt_sht->sh_entsize; + module->symtable_size = crt_sht->sh_size / crt_sht->sh_entsize; + } + if (strcmp(".strtab", sh_strtable + crt_sht->sh_name) == 0) { + // We found the string table + min_offset = MIN(min_offset, crt_sht->sh_offset); + max_offset = MAX(max_offset, crt_sht->sh_offset + crt_sht->sh_size); + max_align = MAX(max_align, crt_sht->sh_addralign); + + str_offset = crt_sht->sh_offset; + + module->strtable_size = crt_sht->sh_size; + } + } + + if (elf_malloc(&module->module_addr, max_align, + max_offset - min_offset) != 0) { + DBG_PRINT("Could not allocate sections\n"); + goto out; + } + + // Copy the data + image_seek(min_offset, module); + image_read(module->module_addr, max_offset - min_offset, module); + + // Setup module information + module->module_size = max_offset - min_offset; + module->str_table = (char*)(module->module_addr + (str_offset - min_offset)); + module->sym_table = module->module_addr + (sym_offset - min_offset); + +out: + // Release the SHT + if (sht != NULL) + free(sht); + + // Release the buffer + if (buffer != NULL) + free(buffer); + + return res; +} + + +int module_load_shallow(struct elf_module *module) { + int res; + Elf32_Ehdr elf_hdr; + + // Do not allow duplicate modules + if (module_find(module->name) != NULL) { + DBG_PRINT("Module already loaded.\n"); + return -1; + } + + res = image_load(module); + + if (res < 0) + return res; + + module->shallow = 1; + + CHECKED(res, image_read(&elf_hdr, sizeof(Elf32_Ehdr), module), error); + + // Checking the header signature and members + CHECKED(res, check_header_shallow(&elf_hdr), error); + + CHECKED(res, load_shallow_sections(module, &elf_hdr), error); + + // Check the symbols for duplicates / missing definitions + CHECKED(res, check_symbols(module), error); + + // Add the module at the beginning of the module list + list_add(&module->list, &modules_head); + + // The file image is no longer needed + image_unload(module); + + DBG_PRINT("SHALLOW MODULE %s LOADED SUCCESSFULLY\n", module->name); + + return 0; + +error: + image_unload(module); + + return res; +} |