aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Bucur <stefan@stefan-mac.(none)>2009-07-03 22:09:16 +0300
committerStefan Bucur <stefan@stefan-mac.(none)>2009-07-03 22:09:16 +0300
commit1ed097522de8d624905efc180e2324acb485e809 (patch)
tree9cae3ad38eeaa1d4920532e745e88e75cbe387ad
parentd6c829e542f6eaea9b750bc05439b2213604ba82 (diff)
parentf79f762a2218dd0741da933533b73e61d67abfff (diff)
downloadsyslinux-elf-1ed097522de8d624905efc180e2324acb485e809.tar.gz
syslinux-elf-1ed097522de8d624905efc180e2324acb485e809.tar.xz
syslinux-elf-1ed097522de8d624905efc180e2324acb485e809.zip
Merged ELF linking from elflink
-rw-r--r--.gitignore4
-rw-r--r--com32/Makefile3
-rw-r--r--com32/elflink/Makefile43
-rw-r--r--com32/elflink/modules/MCONFIG62
-rw-r--r--com32/elflink/modules/Makefile41
-rw-r--r--com32/elflink/modules/README1
-rw-r--r--com32/elflink/modules/hello.c51
-rw-r--r--com32/elflink/modules/sort.c75
-rw-r--r--com32/elflink/modules/sort.h19
-rw-r--r--com32/elflink/test_com32.c203
-rw-r--r--com32/elflink/test_memalign.c47
-rw-r--r--com32/include/klibc/compiler.h6
-rw-r--r--com32/include/linux/list.h463
-rw-r--r--com32/include/stdlib.h24
-rw-r--r--com32/include/sys/elfcommon.h231
-rw-r--r--com32/include/sys/exec.h113
-rw-r--r--com32/include/sys/module.h317
-rw-r--r--com32/lib/Makefile200
-rw-r--r--com32/lib/elf32.ld184
-rw-r--r--com32/lib/free.c118
-rw-r--r--com32/lib/malloc.c193
-rw-r--r--com32/lib/malloc.h31
-rw-r--r--com32/lib/realloc.c70
-rw-r--r--com32/lib/stack.c2
-rw-r--r--com32/lib/sys/module/common.c503
-rw-r--r--com32/lib/sys/module/common.h65
-rw-r--r--com32/lib/sys/module/elf_module.c488
-rw-r--r--com32/lib/sys/module/elfutils.c89
-rw-r--r--com32/lib/sys/module/elfutils.h64
-rw-r--r--com32/lib/sys/module/exec.c174
-rw-r--r--com32/lib/sys/module/shallow_module.c160
31 files changed, 3801 insertions, 243 deletions
diff --git a/.gitignore b/.gitignore
index c7866759..9b746288 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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;
+}