📄 eshlibld.c
字号:
/*!***************************************************************************!*! FILE NAME : eshlibld.c*!*! DESCRIPTION: Dynamic linking and shared library functions.*!*! FUNCTIONS : perform_cris_aout_relocations, shlibmod_fork, shlibmod_exit*! (EXPORTED)*!*!---------------------------------------------------------------------------*!*! (C) Copyright 1998, 1999 Axis Communications AB, LUND, SWEDEN*!*!**************************************************************************//* $Id: eshlibld.c,v 1.12 2000/01/17 11:03:44 hp Exp $ *//* When linking, a list of objects (main program counted as the first, and one for each object needed from a library) object is created: PROG_OBJ - PRELOAD_OBJ1 - PRELOAD_OBJ2 - ... - LIB_OBJ1 - LIB_OBJ2 - ... - LAST_LIB_OBJ. Preloaded objects are inserted just after the program object. The same order as that of a static link is preserved. Each object contains pointers to its .text, .data and .bss, as well as a symbol table and string table. All objects that were needed for a static link are read in first thing. Symbol information for all defined symbols (and the first of any weak symbols) is entered into a global (hashed) symbol table. The "system shared library list" is checked to see if it the wanted object is already present and "shared", or it will be read in from its library file. Every time a symbol is "undefined" in an object (starting with those of the program), the table is searched. There are "customizable" parameters and code that decide if/how many levels of recursions should be done (recursing when an object is linked and relocated and it has undefineds from other objects, that in turn...). FIXME: Add more doc here. *//* Please note that this file is also compiled into the xsim simulator. Try to avoid breaking its double use (only works on a little-endian 32-bit machine such as the i386 anyway). Use __KERNEL__ when you're about to use kernel functions. Use __CRIS__ when you're about to do CRIS-specific code. *//* Make it lose entirely for non-gcc. */#ifndef __GNUC__#error Sorry, gcc-specific code.#endif#ifndef __KERNEL__/* Then it is xsim. */#include <errno.h># include <assert.h># include <stdio.h># include <stdlib.h># include <fcntl.h># include <string.h># include <unistd.h># include <sys/stat.h># include "compiler.h"# include "project.h"# include "risc.h"# include "sim.h"# include "eshlibld.h"#else /* __KERNEL__ */# include <linux/types.h># include <linux/fcntl.h># include <linux/string.h># include <asm/unistd.h># include <linux/stat.h># include <linux/sched.h># include <linux/mman.h># include <asm/a.out.h># include <asm/eshlibld.h># include <linux/mm.h># include <linux/malloc.h># include <asm/io.h> /* Just for simulator debugging macros. */# define assert(x) do {if (!(x)) panic("Assertion failed: " #x); } while (0)# define FILENAME_MAX (NAME_MAX + PATH_MAX + 1)# ifndef NO_MM# error You have to implement stuff to make sure that the address of a# error shared object does not collide with the application or other# error shared objects.# endif/* ! NO_MM */#endif /* __KERNEL__ *//* Generic debug macros and definitions. */#define MAX_DEBUG_F_NAME_LINE_SIZE (64 - 1 - 5 * sizeof(void *))struct memdebug{ struct memdebug *prev; struct memdebug *next; unsigned long is_map; unsigned long amount; char where[MAX_DEBUG_F_NAME_LINE_SIZE + 1]; /* Real chunk follows, or maybe a mmap. */ unsigned long magic_or_map;};#define xstringify(x) #x#define stringify(x) xstringify(x)/* Generic debug stuff. *//* Let's have a lower-intensity level of debug messages; enabling RELOC_DEBUG is not suitable for "narrowing in" on real-world problems (anymore). #undef or #define as suitable. The only effect is a few messages at the begin and end of a relocation, unless something goes wrong, in which case there will be one or a few more messages (hopefully). Actually there will be no messages at all for plain successful relocations (unless you plant some in the caller, in binfmt_aout_cris_flat.c *//* Enabled until I see no bug reports anymore. */#define MINIMAL_RELOC_DEBUG#ifdef MINIMAL_RELOC_DEBUG# define Dm(x) x#else# define Dm(x)#endif/* And one for messages from them both. */#if defined(MINIMAL_RELOC_DEBUG) || defined(RELOC_DEBUG)# define DB(x) x#else# define DB(x)#endif/* Here's the old heavy stuff. */#ifdef RELOC_DEBUG#define DEBUG_ALLOCATED_FILL_VALUE 0xaf#define DEBUG_FREED_FILL_VALUE 0xbf/* Preferrably use this macro for simple one-statement debug prints as seen elsewhere; else use #ifdef RELOC_DEBUG. */#define D_(x) xstatic void *my_debug_malloc(unsigned long, const char *);# define sym_malloc(x, msg) \ my_debug_malloc(x, msg " @" __FUNCTION__ ":" stringify(__LINE__) ".")static void my_debug_free(void *, const char *);# define sym_free(x, msg) \ my_debug_free(x, msg " @" __FUNCTION__ ":" stringify(__LINE__))static void my_note_mmap(unsigned long, unsigned long, const char *);# define note_mmap(x, n, msg) \ my_note_mmap(x, n, msg " @" __FUNCTION__ ":" stringify(__LINE__) "#")# if SHARE_LIB_COREstatic void my_unnote_mmap(unsigned long, const char *);# endif#define unnote_mmap(x, msg) \ my_unnote_mmap(x, msg " @" __FUNCTION__ ":" stringify(__LINE__) "*")struct progenv;static void dump_memusage_before_program(struct progenv *);#if SHARE_LIB_COREstatic void dump_exported(struct progenv *);#else# define dump_exported(x)#endifstatic void move_exported_chunks(void);#else /* ! RELOC_DEBUG */# define D_(x)/* Out-of-memory errors are handled in allocation in the leak-detection harness in the large debug-harness, and just as messages tacked on at failure in this smaller harness. */# ifdef MINIMAL_RELOC_DEBUG# define sym_malloc(x, msg) \ __extension__ ({ \ unsigned long int _nn = (x); \ void *_ptr = real_malloc(_nn); \ if (_ptr == NULL) \ printk("No mem for %lu " msg \ " @" __FUNCTION__ ":" \ stringify(__LINE__) "\n", \ _nn); \ _ptr; \ })# else# define sym_malloc(x, msg) real_malloc(x)# endif /* ! MINIMAL_RELOC_DEBUG */# define sym_free(x, msg) real_free(x)# ifdef MINIMAL_RELOC_DEBUG# define note_mmap(x, n, msg) \ do { \ if (x > 0xffff0000) \ printk("Mmap of %u failed: " \ msg " @" __FUNCTION__ ":" \ stringify(__LINE__) "\n", \ n); \ } while (0);# else# define note_mmap(x, n, msg)# endif/* ! MINIMAL_RELOC_DEBUG */# define unnote_mmap(x, msg)# define dump_memusage_before_program(x)# define dump_exported(x)# define move_exported_chunks()#endif /* ! RELOC_DEBUG *//* The maximum level of objects being traversed to check for dependencies for sharing objects. */ #define MAX_RECURSE 3/* Special symbol names and other string constants. *//* File magic for just plain .o file, as found in libraries and after "cc -c". */#define CRIS_OBJ_MAGIC "\x07\x01\xff\x01"#define MAGIC_SHLIB_SYM " ELINUX SHLIB"#define SYSTEM_CALL_SYMBOL ".$System.call"#define CHEATED_WRITABLE_DATA_SYMBOL ".$contains.cheated.writable.data"#define ARFILENAMES_NAME "ARFILENAMES/"#define ARFILE_MAGIC "!<arch>\n"#define PROGRAM_SYMBOLS_SYMBOL ".$address.of.my.symbols"#define GLOBAL_CTOR_PREFIX "__GLOBAL_$I$"#define GLOBAL_DTOR_PREFIX "__GLOBAL_$D$"#define GLOBAL_LIB_CTOR_LIST ".$global.lib.ctors"#define GLOBAL_LIB_DTOR_LIST ".$global.lib.dtors"#define PRELOAD_MAIN "__preload_main_"/* Using lots of macros in trying to keep this compilable for easy debugging in gdb, as part of the simulator. */#ifdef __KERNEL__# define real_malloc(x) kmalloc(x, GFP_KERNEL)# define real_free(x) kfree(x)/* FIXME: These system calls aren't really right, but there does not seem to be convenient do_XXX functions where there are sys_XXX equivalents. The sys_XXX functions are wrong because they assume arguments live in user space, and where there are do_XXX functions, they do not generally have compatible parameters with the sys_XXX functions. */extern asmlinkage int sys_open(const char *,int,int);# define sym_open(fname) sys_open(fname, 0, 0)extern int sys_read(int, char *, int);# define sym_read sys_readextern int sys_write(int, const char *, int);# define sym_write sys_writeextern int sys_close(unsigned int);# define sym_close sys_closeextern long sys_lseek(unsigned int, off_t, unsigned int);# define sym_lseek sys_lseekextern int namei(const char *, struct inode **);# define sym_namei(name) \ __extension__ ({ struct inode *buf; namei(name, &buf); })# define fatal_never_tried() \ panic("a.out-relocate: OOPS! Never debugged this code in " __FUNCTION__ "!\n")# define debug_fatal panic# define sym_mmap(thefd, addr, len, protection, flags, offset, msg) \ __extension__ \ ({ \ struct file *_Ffile \ = thefd < 0 ? NULL : current->files->fd[thefd]; \ unsigned long _m \ = do_mmap(_Ffile, addr, len, protection, \ flags, offset); \ note_mmap(_m, len, msg); \ _m; \ })# define sym_mforgetmap(x, msg) \ do { unnote_mmap(x, msg); do_mforgetmap(x); } while (0)# define readdw(x) *(unsigned long *) (x)# define writedw(x,y) *(unsigned long *) (x) = (y)#else /* ! __KERNEL__ *//* Equivalent to what's in a.out.h, but we don't have it when ! __KERNEL__, so we cheat here. */ struct aout_cris_exec{ char magic[4]; /* Use macros N_MAGIC, etc for access. */ unsigned a_text; /* Length of text, in bytes. */ unsigned a_data; /* Length of data, in bytes. */ unsigned a_bss; /* Length of uninitialized data area for file, in bytes. */ unsigned a_syms; /* Length of symbol table data in file, in bytes. */ unsigned a_stringsize; /* Used to be "start address", but why start anywhere else than at the beginning (at "reserved", below. Also saves an mmap call. */ unsigned a_trsize; /* Length of relocation info for text, in bytes. */ unsigned a_drsize; /* Length of relocation info for data, in bytes. */ char reserved[8]; /* Jump instruction(s) to start, maybe. */ unsigned long stack_hint; /* At least this big stack. */};# define sym_mmap(thefd, addr, len, protection, flags, offset, msg) \ __extension__ \ ({ \ unsigned long _Endmem = states->endmem; \ unsigned long _Llength = (((len) + 31) &~31); \ create_mem_block(states->endmem,_Llength); \ memset(get_mem_ptr(_Endmem, SIMULATOR_ACCESS), 0, (len)); \ note_mmap(_Endmem, len, msg); \ states->endmem += _Llength; \ \ (thefd) < 0 \ ? _Endmem \ : (lseek((thefd), offset, 0) == (off_t) (offset) \ && read((thefd), \ get_mem_ptr(_Endmem, SIMULATOR_ACCESS), \ (len)) \ == (ssize_t) (len) \ ? _Endmem : -1); \ })# define sym_mforgetmap(x, msg) unnote_mmap(x, msg)# define sym_open(path) \ __extension__ ({ \ int _res = open(path, 0); \ if (_res < 0) \ _res = -errno; \ _res; \ })# define sym_close closeextern void illegal(char *s);# define fatal_never_tried() illegal("execution path (Never debugged code)!")# define debug_fatal(f, a...) \ __extension__ \ ({ \ char _s[200]; \ snprintf(_s, sizeof(_s) - 1, f, ## a); \ strcat(_s, "\n"); \ illegal(_s); \ })/* Please don't use "naked" printk:s in the code. */# define printk printf# define real_malloc malloc# define real_free free# define sym_lseek lseek# define sym_read read# define sym_write write/* The linux simple_strtoul has a subset of the strtoul functionality. */# define simple_strtoul strtoul# define sym_namei(name) \ __extension__ ({ struct stat buf; stat(name, &buf); })# define readdw(x) read_dword((unsigned long) x, SIMULATOR_ACCESS)# define writedw(x,y) write_dword((unsigned long) (x),(y), SIMULATOR_ACCESS)#endif /* ! __KERNEL__ *//* Generic program-specific macros. *//* This is used in "tracing" output, when LD_TRACE_LOADED_OBJECTS. */#define sym_str(x) sym_write(2, x, strlen(x))/* What kind of symbol is it? */#define SYMTYPE(x) ((x) & 0x1e)/* Weaks are global. */#define SYM_IS_GLOBAL(x) (((x) & 1) || ((x) & 0x1f) > WEAK_SYM)/* Weaks are global. */#define SYM_IS_GLOBAL_STRONG_KNOWN(x) \ (((x) & 1) && ((x) & 0x1e) != 0 && ((x) & 0x1f) <= BSS_SYM)/* Weaks are counted as "known" here. */#define SYM_IS_KNOWN(x) \ (((x) & 0x1e) != 0 && ((x) & 0x1e) != WEAK_SYM \ && ((x) & 0x1f) <= WEAK_B_SYM)#define SYM_IS_WEAK(x) \ (((x) & 0x1f) >= WEAK_A_SYM && ((x) & 0x1f) <= WEAK_B_SYM)/* Symbol types. */#define UNKNOWN_SYM 0#define ABS_SYM 2#define TEXT_SYM 4#define DATA_SYM 6#define BSS_SYM 8#define WEAK_SYM 12#define WEAK_A_SYM 14#define WEAK_T_SYM 15#define WEAK_D_SYM 16#define WEAK_B_SYM 17/* Segsym contains subfields; but I (and gcc) like extraction macros rather than bitfields and such. */#define RELOCTYPE(segsym) (((segsym) >> 24) & 3)/* Only accepted reloc-type. Others are errors. Only way it may break is with assembly code. */#define RELOC_32 2/* (Maybe) used to mark that relocation has been performed. BFD for CRIS already errors on this as input so it shold be OK. */#define RELOC_DONE 3#define SEGMENT(segsym) ((segsym) & 0xffffff)/* Valid segments to relocate to. *//* We shouldn't really have relocs to the "absolute" segment and (besides it should have the value 2 not 0); this shouldn't happen. But due to a bug in binutils-2.6 (maybe later versions), relocs seemingly to be against the absolute segment (and even with the wrong segment number - solved in 2.7) can happen as the result of an "ld -r -o foo.o -defsym weak_symbol=0 foo1.o foo2.o && strip -N weak_symbol foo.o". Of course those relocs should have been resolved at the "ld -r", and should not be there at all when we get here. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -