From 395ae7d90879d39bb9db268125ae7ef05ea46282 Mon Sep 17 00:00:00 2001 From: "KJK::Hyperion" Date: Thu, 30 Dec 2004 05:59:11 +0000 Subject: [PATCH] - PSEH changes imported in the main tree - initial (dead, disabled) import of ELF support svn path=/trunk/; revision=12398 --- reactos/include/elf.h | 492 +--- reactos/include/elf/common.h | 392 +++ reactos/include/elf/elf-i386.h | 153 ++ reactos/include/elf/elf32.h | 154 ++ reactos/include/elf/elf64.h | 167 ++ reactos/include/elf/generic.h | 87 + reactos/include/elf/machine.h | 12 + reactos/include/pe.h | 73 +- reactos/include/pseh.h | 44 + reactos/include/pseh/framebased.h | 77 +- reactos/include/pseh/framebased/internal.h | 2 +- reactos/include/reactos/exeformat.h | 100 + reactos/lib/ntdll/ldr/elf.c | 2822 ++++++++++++++++++++ reactos/lib/ntdll/ldr/tls.c | 127 - reactos/lib/pseh/i386/framebased.asm | 2 - reactos/lib/pseh/i386/setjmp.asm | 2 - reactos/ntoskrnl/mm/elf.c | 702 +++++ reactos/ntoskrnl/mm/elf32.c | 145 + reactos/ntoskrnl/mm/elf64.c | 2 + reactos/ntoskrnl/mm/pe.c | 745 ++++++ 20 files changed, 5675 insertions(+), 625 deletions(-) create mode 100644 reactos/include/elf/common.h create mode 100644 reactos/include/elf/elf-i386.h create mode 100644 reactos/include/elf/elf32.h create mode 100644 reactos/include/elf/elf64.h create mode 100644 reactos/include/elf/generic.h create mode 100644 reactos/include/elf/machine.h create mode 100644 reactos/include/reactos/exeformat.h create mode 100644 reactos/lib/ntdll/ldr/elf.c delete mode 100644 reactos/lib/ntdll/ldr/tls.c create mode 100644 reactos/ntoskrnl/mm/elf.c create mode 100644 reactos/ntoskrnl/mm/elf32.c create mode 100644 reactos/ntoskrnl/mm/elf64.c create mode 100644 reactos/ntoskrnl/mm/pe.c diff --git a/reactos/include/elf.h b/reactos/include/elf.h index 1b2a7344b5e..70f290840e1 100644 --- a/reactos/include/elf.h +++ b/reactos/include/elf.h @@ -1,488 +1,20 @@ -#ifndef __INCLUDE_ELF_H -#define __INCLUDE_ELF_H +#ifndef _REACTOS_ELF_H_ +#define _REACTOS_ELF_H_ 1 - -#ifdef __64BITS__ /* FIXME: how to check for 64 bits? */ -# define ELF_ARCH_SIZE 64 -#else -# define ELF_ARCH_SIZE 32 -#endif - - -/* 32-bit data types */ -typedef unsigned long ELF32_ADDR; /* Unsigned program address */ -typedef unsigned short ELF32_HALF; /* Unsigned medium integer */ -typedef unsigned long ELF32_OFF; /* Unsigned file offset */ -typedef unsigned long ELF32_SWORD; /* Signed large integer */ -typedef unsigned long ELF32_WORD; /* Unsigned large integer */ -typedef ELF32_OFF ELF32_HASHELT; /* Hash element? */ - -/* Elf data encodings */ -#define IMAGE_ELF_DATA_NONE 0 /* Invalid data encoding */ -#define IMAGE_ELF_DATA_2LSB 1 /* 2's complement, LSB first */ -#define IMAGE_ELF_DATA_2MSB 2 /* 2's complement, MSB first */ - -/* Elf object file types */ -#define IMAGE_ELF_TYPE_NONE 0 /* No file type */ -#define IMAGE_ELF_TYPE_REL 1 /* Relocatable file */ -#define IMAGE_ELF_TYPE_EXEC 2 /* Executable file */ -#define IMAGE_ELF_TYPE_DYN 3 /* Shared object file */ -#define IMAGE_ELF_TYPE_CORE 4 /* Core file */ - -/* Elf machines */ -#define IMAGE_ELF_MACHINE_NONE 0 /* No machine */ -#define IMAGE_ELF_MACHINE_M32 1 /* AT&T WE 32100 */ -#define IMAGE_ELF_MACHINE_SPARC 2 /* SPARC */ -#define IMAGE_ELF_MACHINE_386 3 /* Intel 80386 */ -#define IMAGE_ELF_MACHINE_68K 4 /* Motorola 68000 */ -#define IMAGE_ELF_MACHINE_88K 5 /* Motorola 88000 */ - /* 6 is reserved */ -#define IMAGE_ELF_MACHINE_860 7 /* Intel 80860 */ -#define IMAGE_ELF_MACHINE_MIPS 8 /* MIPS RS3000 (MIPS I) */ -#define IMAGE_ELF_MACHINE_S370 9 /* IBM System/370 Processor */ -#define IMAGE_ELF_MACHINE_MIPS_RS3_LE 10 /* MIPS RS3000 Little-endian */ - /* 11-14 are reserved */ -#define IMAGE_ELF_MACHINE_PARISC 15 /* Hewlett-Packard PA-RISC */ - /* 16 is reserved */ -#define IMAGE_ELF_MACHINE_VPP500 17 /* Fujitsu VPP500 */ -#define IMAGE_ELF_MACHINE_SPARC32PLUS 18 /* Enhanced instruction set SPARC */ -#define IMAGE_ELF_MACHINE_960 19 /* Intel 80960 */ -#define IMAGE_ELF_MACHINE_PPC 20 /* PowerPC */ -#define IMAGE_ELF_MACHINE_PPC64 21 /* 64-bit PowerPC */ - /* 22-35 are reserved */ -#define IMAGE_ELF_MACHINE_V800 36 /* NEC V800 */ -#define IMAGE_ELF_MACHINE_FR20 37 /* Fujitsu FR20 */ -#define IMAGE_ELF_MACHINE_RH32 38 /* TRW RH-32 */ -#define IMAGE_ELF_MACHINE_RCE 39 /* Motorola RCE */ -#define IMAGE_ELF_MACHINE_ARM 40 /* Advanced RISC Machines ARM */ -#define IMAGE_ELF_MACHINE_ALPHA 41 /* Digital Alpha */ -#define IMAGE_ELF_MACHINE_SH 42 /* Hitachi SH */ -#define IMAGE_ELF_MACHINE_SPARCV9 43 /* SPARC Version 9 */ -#define IMAGE_ELF_MACHINE_TRICORE 44 /* Siemens Tricore embedded processor */ -#define IMAGE_ELF_MACHINE_ARC 45 /* Argonaut RISC Core, Argonaut Technologies Inc. */ -#define IMAGE_ELF_MACHINE_H8_300 46 /* Hitachi H8/300 */ -#define IMAGE_ELF_MACHINE_H8_300H 47 /* Hitachi H8/300H */ -#define IMAGE_ELF_MACHINE_H8S 48 /* Hitachi H8S */ -#define IMAGE_ELF_MACHINE_H8_500 49 /* Hitachi H8/500 */ -#define IMAGE_ELF_MACHINE_IA_64 50 /* Intel IA-64 processor architecture */ -#define IMAGE_ELF_MACHINE_MIPS_X 51 /* Stanford MIPS-X */ -#define IMAGE_ELF_MACHINE_COLDFIRE 52 /* Motorola ColdFire */ -#define IMAGE_ELF_MACHINE_68HC12 53 /* Motorola M68HC12 */ -#define IMAGE_ELF_MACHINE_MMA 54 /* Fujitsu MMA Multimedia Accelerator */ -#define IMAGE_ELF_MACHINE_PCP 55 /* Siemens PCP */ -#define IMAGE_ELF_MACHINE_NCPU 56 /* Sony nCPU embedded RISC processor */ -#define IMAGE_ELF_MACHINE_NDR1 57 /* Denso NDR1 microprocessor */ -#define IMAGE_ELF_MACHINE_STARCORE 58 /* Motorola Star*Core processor */ -#define IMAGE_ELF_MACHINE_ME16 59 /* Toyota ME16 processor */ -#define IMAGE_ELF_MACHINE_ST100 60 /* STMicroelectronics ST100 processor */ -#define IMAGE_ELF_MACHINE_TINYJ 61 /* Advanced Logic Corp. TinyJ embedded processor family */ - /* 62-65 are reserved */ -#define IMAGE_ELF_MACHINE_FX66 66 /* Siemens FX66 microcontroller */ -#define IMAGE_ELF_MACHINE_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 bit microcontroller */ -#define IMAGE_ELF_MACHINE_ST7 68 /* STMicroelectronics ST7 8-bit microcontroller */ -#define IMAGE_ELF_MACHINE_68HC16 69 /* Motorola MC68HC16 Microcontroller */ -#define IMAGE_ELF_MACHINE_68HC11 70 /* Motorola MC68HC11 Microcontroller */ -#define IMAGE_ELF_MACHINE_68HC08 71 /* Motorola MC68HC08 Microcontroller */ -#define IMAGE_ELF_MACHINE_68HC05 72 /* Motorola MC68HC05 Microcontroller */ -#define IMAGE_ELF_MACHINE_SVX 73 /* Silicon Graphics SVx */ -#define IMAGE_ELF_MACHINE_ST19 74 /* STMicroelectronics ST19 8-bit microcontroller */ -#define IMAGE_ELF_MACHINE_VAX 75 /* Digital VAX */ -#define IMAGE_ELF_MACHINE_CRIS 76 /* Axis Communications 32-bit embedded processor */ -#define IMAGE_ELF_MACHINE_JAVELIN 77 /* Infineon Technologies 32-bit embedded processor */ -#define IMAGE_ELF_MACHINE_FIREPATH 78 /* Element 14 64-bit DSP Processor */ -#define IMAGE_ELF_MACHINE_ZSP 79 /* LSI Logic 16-bit DSP Processor */ -#define IMAGE_ELF_MACHINE_MMIX 80 /* Donald Knuth's educational 64-bit processor */ -#define IMAGE_ELF_MACHINE_HUANY 81 /* Harvard University machine-independent object files */ -#define IMAGE_ELF_MACHINE_PRISM 82 /* SiTera Prism */ -#define IMAGE_ELF_MACHINE_AVR 83 /* Atmel AVR 8-bit microcontroller */ -#define IMAGE_ELF_MACHINE_FR30 84 /* Fujitsu FR30 */ -#define IMAGE_ELF_MACHINE_D10V 85 /* Mitsubishi D10V */ -#define IMAGE_ELF_MACHINE_D30V 86 /* Mitsubishi D30V */ -#define IMAGE_ELF_MACHINE_V850 87 /* NEC v850 */ -#define IMAGE_ELF_MACHINE_M32R 88 /* Mitsubishi M32R */ -#define IMAGE_ELF_MACHINE_MN10300 89 /* Matsushita MN10300 */ -#define IMAGE_ELF_MACHINE_MN10200 90 /* Matsushita MN10200 */ -#define IMAGE_ELF_MACHINE_PJ 91 /* picoJava */ -#define IMAGE_ELF_MACHINE_OPENRISC 92 /* OpenRISC 32-bit embedded processor */ - -/* Elf versions */ -#define IMAGE_ELF_VERSION_NONE 0 /* Invalid version */ -#define IMAGE_ELF_VERSION_CURRENT 1 /* Current version */ - -/* Elf identification */ -#define IMAGE_ELF_SIZEOF_IDENT 16 -#define IMAGE_ELF_IDENT_MAGIC0 0 /* Magic */ -#define IMAGE_ELF_IDENT_MAGIC1 1 -#define IMAGE_ELF_IDENT_MAGIC2 2 -#define IMAGE_ELF_IDENT_MAGIC3 3 -#define IMAGE_ELF_IDENT_CLASS 4 /* File class */ -#define IMAGE_ELF_IDENT_DATA 5 /* Data encoding */ -#define IMAGE_ELF_IDENT_VERSION 6 /* File version */ -#define IMAGE_ELF_IDENT_OSABI 7 /* Operating system/ABI identification */ -#define IMAGE_ELF_IDENT_ABIVERSION 8 /* ABI version */ -#define IMAGE_ELF_IDENT_PAD 9 /* Start of padding bytes */ - -/* Magic numbers */ -#define IMAGE_ELF_MAGIC0 0x7f -#define IMAGE_ELF_MAGIC1 'E' -#define IMAGE_ELF_MAGIC2 'L' -#define IMAGE_ELF_MAGIC3 'F' - -/* Elf file classes */ -#define IMAGE_ELF_CLASS_NONE 0 /* Invalid class */ -#define IMAGE_ELF_CLASS_32 1 /* 32-bit object */ -#define IMAGE_ELF_CLASS_64 2 /* 64-bit object */ - -/* Check elf magic */ -#define IMAGE_IS_ELF(hdr) ((hdr).Ident[IMAGE_ELF_IDENT_MAGIC0] == IMAGE_ELF_MAGIC0 && \ - (hdr).Ident[IMAGE_ELF_IDENT_MAGIC1] == IMAGE_ELF_MAGIC1 && \ - (hdr).Ident[IMAGE_ELF_IDENT_MAGIC2] == IMAGE_ELF_MAGIC2 && \ - (hdr).Ident[IMAGE_ELF_IDENT_MAGIC3] == IMAGE_ELF_MAGIC3) - - - -/* 32-bit Elf header */ -typedef struct _IMAGE_ELF32_HEADER { - unsigned char Ident[IMAGE_ELF_SIZEOF_IDENT]; /* Identification */ - ELF32_HALF Type; /* Object file type */ - ELF32_HALF Machine; /* Required architecture */ - ELF32_WORD Version; /* Object file version */ - ELF32_ADDR Entry; /* Virtual address of entry point */ - ELF32_OFF PhOff; /* Program header table offset in file */ - ELF32_OFF ShOff; /* Section header offset in file */ - ELF32_WORD Flags; /* Processor specific flags - zero for SPARC and x86 */ - ELF32_HALF EhSize; /* Elf header size in bytes (this struct) */ - ELF32_HALF PhEntSize; /* Size of an entry in the program header table */ - ELF32_HALF PhNum; /* Number of entries in the program header table */ - ELF32_HALF ShEntSize; /* Size of an entry in the section header table */ - ELF32_HALF ShNum; /* Number of entries in the section header table */ - ELF32_HALF ShStrNdx; /* Index into the section header table for the entry of the section name string table */ -} IMAGE_ELF32_HEADER, *PIMAGE_ELF32_HEADER; - - - - - -/* Special section indexes */ -#define IMAGE_ELF_SECTION_INDEX_UNDEF 0 -/*#define IMAGE_ELF_SECTION_INDEX_LORESERVE 0xff00 -#define IMAGE_ELF_SECTION_INDEX_LOPROC 0xff00 -#define IMAGE_ELF_SECTION_INDEX_HIPROC 0xff1f*/ -#define IMAGE_ELF_SECTION_INDEX_ABS 0xfff1 -#define IMAGE_ELF_SECTION_INDEX_COMMON 0xfff2 -/*#define IMAGE_ELF_SECTION_INDEX_HIRESERVE 0xffff*/ - -/* Section types */ -#define IMAGE_ELF_SECTION_TYPE_NULL 0 /* Incactive section header */ -#define IMAGE_ELF_SECTION_TYPE_PROGBITS 1 /* Program defined section */ -#define IMAGE_ELF_SECTION_TYPE_SYMTAB 2 /* Symbol table (for link editing) */ -#define IMAGE_ELF_SECTION_TYPE_STRTAB 3 /* String table */ -#define IMAGE_ELF_SECTION_TYPE_RELA 4 /* Relocation table (with explicit addends) */ -#define IMAGE_ELF_SECTION_TYPE_HASH 5 /* Symbol hash table */ -#define IMAGE_ELF_SECTION_TYPE_DYNAMIC 6 /* Information for dynamic linking */ -#define IMAGE_ELF_SECTION_TYPE_NOTE 7 /* Note section ;-) */ -#define IMAGE_ELF_SECTION_TYPE_NOBITS 8 /* Occupies no space in the file, otherwise like PROGBITS */ -#define IMAGE_ELF_SECTION_TYPE_REL 9 /* Relocation table (without explicit addends) */ -#define IMAGE_ELF_SECTION_TYPE_SHLIB 10 /* Reserved, unspecified */ -#define IMAGE_ELF_SECTION_TYPE_DYNSYM 11 /* Symbol table (for dynamic linking) */ -/*#define IMAGE_ELF_SECTION_TYPE_LOPROC 0x70000000 -#define IMAGE_ELF_SECTION_TYPE_HIPROC 0x7fffffff -#define IMAGE_ELF_SECTION_TYPE_LOUSER 0x80000000 -#define IMAGE_ELF_SECTION_TYPE_HIUSER 0xffffffff*/ - -/* Section flags/attributes */ -#define SHF_WRITE 0x1 /* Section must be writeable */ -#define SHF_ALLOC 0x2 /* Section must be loaded/mapped into memory */ -#define SHF_EXECINSTR 0x4 /* The section contains executable code */ -/*#define SHF_MASKPROC 0xf0000000*/ - -/* 32-bit Section header entry */ -typedef struct _IMAGE_ELF32_SECTION_HEADER { - ELF32_WORD Name; /* Name of the section (index into the section header string table) */ - ELF32_WORD Type; /* Type of section */ - ELF32_WORD Flags; /* Attributes */ - ELF32_ADDR Addr; /* Virtual address to load section at */ - ELF32_OFF Offset; /* Offset into the file of the section's data */ - ELF32_WORD Size; /* Size of the section */ - ELF32_WORD Link; /* Section header table index link... */ - ELF32_WORD Info; /* Extra information... */ - ELF32_WORD AddrAlign; /* Required alignment */ - ELF32_WORD EntSize; /* Size of entries in the table */ -} IMAGE_ELF32_SECTION_HEADER, *PIMAGE_ELF32_SECTION_HEADER; - - - - - -/* Symbol table indexes */ -#define IMAGE_ELF_SYMBOL_INDEX_UNDEF 0 /* Undefined symbol */ - -/* Symbol binding/types */ -#define IMAGE_ELF32_SYMBOL_BIND(Info) ((Info) >> 4) -#define IMAGE_ELF32_SYMBOL_TYPE(Info) ((Info) & 0x0f) -#define IMAGE_ELF32_SYMBOL_INFO(Bind, Type) (((Bind) << 4) | ((Type) & 0x0f)) - -#define IMAGE_ELF_SYMBOL_BINDING_LOCAL 0 /* Local ("static") symbol */ -#define IMAGE_ELF_SYMBOL_BINDING_GLOBAL 1 /* Global symbol */ -#define IMAGE_ELF_SYMBOL_BINDING_WEAK 2 /* Weak symbol... */ -/*#define IMAGE_ELF_SYMBOL_BINDING_LOPROC 13 -#define IMAGE_ELF_SYMBOL_BINDING_HIPROC 15*/ - -#define IMAGE_ELF_SYMBOL_TYPE_NOTYPE 0 /* Unspecified symbol type */ -#define IMAGE_ELF_SYMBOL_TYPE_OBJECT 1 /* Data object (i.e. an array, variable, ...) */ -#define IMAGE_ELF_SYMBOL_TYPE_FUNC 2 /* Function (or other executable code) */ -#define IMAGE_ELF_SYMBOL_TYPE_SECTION 3 /* Symbol for relocating (usually has local binding) */ -#define IMAGE_ELF_SYMBOL_TYPE_FILE 4 /* Name of the associated source file */ -#define IMAGE_ELF_SYMBOL_TYPE_LOPROC 13 -#define IMAGE_ELF_SYMBOL_TYPE_HIPROC 15 - -/* 32-bit Symbol entry */ -typedef struct _IMAGE_ELF32_SYMBOL { - ELF32_WORD Name; /* Symbol name (index into the symbol string table) */ - ELF32_ADDR Value; /* Value of symbol */ - ELF32_WORD Size; /* Size of symbol (0 means unknown) */ - unsigned char Info; /* Type and binding attributes */ - unsigned char Other; /* Unused - 0 */ - ELF32_HALF Shndx; /* Section index */ -} IMAGE_ELF32_SYMBOL, *PIMAGE_ELF32_SYMBOL; - - - - - -/* Relocation macros */ -#define IMAGE_ELF32_RELOC_SYM(Info) ((Info) >> 8) -#define IMAGE_ELF32_RELOC_TYPE(Info) ((unsigned char)(Info)) -#define IMAGE_ELF32_RELOC_INFO(Sym,Type) (((Sym) << 8) | (unsigned char)(Type)) - -/* 386 Relocation types */ -#define IMAGE_ELF_RELOC_386_NONE 0 /* none */ -#define IMAGE_ELF_RELOC_386_32 1 -#define IMAGE_ELF_RELOC_386_PC32 2 -#define IMAGE_ELF_RELOC_386_GOT32 3 -#define IMAGE_ELF_RELOC_386_PLT32 4 -#define IMAGE_ELF_RELOC_386_COPY 5 -#define IMAGE_ELF_RELOC_386_GLOB_DAT 6 -#define IMAGE_ELF_RELOC_386_JMP_SLOT 7 -#define IMAGE_ELF_RELOC_386_RELATIVE 8 -#define IMAGE_ELF_RELOC_386_GOTOFF 9 -#define IMAGE_ELF_RELOC_386_GOTPC 10 - -/* 386 TLS Relocation types */ -#define IMAGE_ELF_RELOC_386_TLS_GD_PLT 12 -#define IMAGE_ELF_RELOC_386_TLS_LDM_PLT 13 -#define IMAGE_ELF_RELOC_386_TLS_TPOFF 14 -#define IMAGE_ELF_RELOC_386_TLS_IE 15 -#define IMAGE_ELF_RELOC_386_TLS_GOTIE 16 -#define IMAGE_ELF_RELOC_386_TLS_LE 17 -#define IMAGE_ELF_RELOC_386_TLS_GD 18 -#define IMAGE_ELF_RELOC_386_TLS_LDM 19 -#define IMAGE_ELF_RELOC_386_TLS_LDO_32 32 -#define IMAGE_ELF_RELOC_386_TLS_DTPMOD32 35 -#define IMAGE_ELF_RELOC_386_TLS_DTPOFF32 36 - -/* 32-bit Relocation entries */ -typedef struct _IMAGE_ELF32_RELOC { - ELF32_ADDR Offset; /* Section offset/virtual address */ - ELF32_WORD Info; /* Symbol table index/relocation type */ -} IMAGE_ELF32_RELOC, *PIMAGE_ELF32_RELOC; - -typedef struct _IMAGE_ELF32_RELOCA { - ELF32_ADDR Offset; /* Section offset/virtual address */ - ELF32_WORD Info; /* Symbol table index/relocation type */ - ELF32_SWORD Addend; /* Addend */ -} IMAGE_ELF32_RELOCA, *PIMAGE_ELF32_RELOCA; - - - - - -/* Program header/segment types */ -#define IMAGE_ELF_SEGMENT_TYPE_NULL 0 /* Unused array entry */ -#define IMAGE_ELF_SEGMENT_TYPE_LOAD 1 /* Loadable segment */ -#define IMAGE_ELF_SEGMENT_TYPE_DYNAMIC 2 /* Dynamic linking info... */ -#define IMAGE_ELF_SEGMENT_TYPE_INTERP 3 /* Interpreter */ -#define IMAGE_ELF_SEGMENT_TYPE_NOTE 4 /* Note... */ -#define IMAGE_ELF_SEGMENT_TYPE_SHLIB 5 /* Reserved but unspecified */ -#define IMAGE_ELF_SEGMENT_TYPE_PHDR 6 /* Program header table */ -#define IMAGE_ELF_SEGMENT_TYPE_TLS 7 /* Thread local storage */ - -#define IMAGE_ELF_SEGMENT_TYPE_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */ -#define IMAGE_ELF_SEGMENT_TYPE_GNU_STACK 0x6474e551 /* Indicates stack executability */ -/*#define IMAGE_ELF_SEGMENT_TYPE_LOPROC 0x70000000 -#define IMAGE_ELF_SEGMENT_TYPE_HIPROC 0x7fffffff*/ - -/* Program header/segment flags */ -#define IMAGE_ELF_SEGMENT_FLAG_EXEC 0x01 -#define IMAGE_ELF_SEGMENT_FLAG_WRITE 0x02 -#define IMAGE_ELF_SEGMENT_FLAG_READ 0x04 -/*#define IMAGE_ELF_SEGMENT_FLAG_MASKPROC 0xf0000000*/ - -/* 32-bit Program header entry */ -typedef struct _IMAGE_ELF32_PROGRAM_HEADER { - ELF32_WORD Type; /* Type of segment */ - ELF32_OFF Offset; /* File offset of segment data */ - ELF32_ADDR VAddr; /* Virtual address to load segment at */ - ELF32_ADDR PAddr; /* Physical address to load segment at */ - ELF32_WORD FileSz; /* Size in file of segment */ - ELF32_WORD MemSz; /* Size in memory of segment */ - ELF32_WORD Flags; /* Flags of segment */ - ELF32_WORD Align; /* Required alignment */ -} IMAGE_ELF32_PROGRAM_HEADER, *PIMAGE_ELF32_PROGRAM_HEADER; - - - - - -/* Dynamic array tags */ -#define IMAGE_ELF_DYNAMIC_TAG_NULL 0 /* End of array */ -#define IMAGE_ELF_DYNAMIC_TAG_NEEDED 1 /* Dependency */ -#define IMAGE_ELF_DYNAMIC_TAG_PLTRELSZ 2 /* Size in bytes of the relocation entries associated with the plt */ -#define IMAGE_ELF_DYNAMIC_TAG_PLTGOT 3 /* Address associated with got/plt */ -#define IMAGE_ELF_DYNAMIC_TAG_HASH 4 /* Hash table for symbol table indicated by SYMTAB */ -#define IMAGE_ELF_DYNAMIC_TAG_STRTAB 5 /* Address of string table */ -#define IMAGE_ELF_DYNAMIC_TAG_SYMTAB 6 /* Address of the symbol table */ -#define IMAGE_ELF_DYNAMIC_TAG_RELA 7 /* Address of reloc table with addends */ -#define IMAGE_ELF_DYNAMIC_TAG_RELASZ 8 /* Size of reloc table in bytes */ -#define IMAGE_ELF_DYNAMIC_TAG_RELAENT 9 /* Size of reloc table entry in bytes? */ -#define IMAGE_ELF_DYNAMIC_TAG_STRSZ 10 /* Size of the string table in bytes */ -#define IMAGE_ELF_DYNAMIC_TAG_SYMENT 11 /* Size of symbol table entry in bytes */ -#define IMAGE_ELF_DYNAMIC_TAG_INIT 12 /* Address of initialization function */ -#define IMAGE_ELF_DYNAMIC_TAG_FINI 13 /* Address of termination function */ -#define IMAGE_ELF_DYNAMIC_TAG_SONAME 14 /* Name of the shared object (string table offset) */ -#define IMAGE_ELF_DYNAMIC_TAG_RPATH 15 /* Library search path (string table offset) */ -#define IMAGE_ELF_DYNAMIC_TAG_SYMBOLIC 16 /* Alter runtime-linkers symbol resolution... */ -#define IMAGE_ELF_DYNAMIC_TAG_REL 17 /* Address of reloc table without addends */ -#define IMAGE_ELF_DYNAMIC_TAG_RELSZ 18 /* Size of reloc table in bytes */ -#define IMAGE_ELF_DYNAMIC_TAG_RELENT 19 /* Size of reloc table entry in bytes? */ -#define IMAGE_ELF_DYNAMIC_TAG_PLTREL 20 /* Type of relocation entry for plt (...TAG_REL or ...TAG_RELA) */ -#define IMAGE_ELF_DYNAMIC_TAG_DEBUG 21 /* Used for debugging */ -#define IMAGE_ELF_DYNAMIC_TAG_TEXTREL 22 /* If present informs the linker that a relocation might update a non-writable segment */ -#define IMAGE_ELF_DYNAMIC_TAG_JMPREL 23 /* Address of relocation entries associated solely with the plt */ -#define IMAGE_ELF_DYNAMIC_TAG_FILTER 24 /* Specifies the name of a shared objects for which this one acts as a filter */ - -#define IMAGE_ELF_DYNAMIC_TAG_RUNPATH 29 /* String table offset of a null-terminated library search path string. */ -#define IMAGE_ELF_DYNAMIC_TAG_FLAGS 30 /* Object specific flag values. */ - -/* Dynamic flags (for IMAGE_ELF_DYNAMIC_TAG_FLAGS) */ -#define IMAGE_ELF_DYNAMIC_FLAG_ORIGIN 0x0001 /* Indicates that the object being loaded may make reference to the $ORIGIN substitution string.*/ -#define IMAGE_ELF_DYNAMIC_FLAG_SYMBOLIC 0x0002 /* Indicates "symbolic" linking. */ -#define IMAGE_ELF_DYNAMIC_FLAG_TEXTREL 0x0004 /* Indicates there may be relocations in non-writable segments. */ -#define IMAGE_ELF_DYNAMIC_FLAG_BIND_NOW 0x0008 /* Indicates that the dynamic linker should process all relocations for the object - containing this entry before transferring control to the program. */ -#define IMAGE_ELF_DYNAMIC_FLAG_STATIC_TLS 0x0010 /* Indicates that the shared object or executable contains code using a static - thread-local storage scheme. */ - -/* Dynamic array entry */ -typedef struct _IMAGE_ELF32_DYNAMIC { - ELF32_SWORD Tag; - union { - ELF32_WORD Val; - ELF32_ADDR Ptr; - } Un; -} IMAGE_ELF32_DYNAMIC, *PIMAGE_ELF32_DYNAMIC; - - - - - -/* Auxiliary types */ -#define IMAGE_ELF_AUX_TYPE_NULL 0 /* Terminates the vector. */ -#define IMAGE_ELF_AUX_TYPE_IGNORE 1 /* Ignored entry. */ -#define IMAGE_ELF_AUX_TYPE_EXECFD 2 /* File descriptor of program to load. */ -#define IMAGE_ELF_AUX_TYPE_PHDR 3 /* Program header of program already loaded. */ -#define IMAGE_ELF_AUX_TYPE_PHENT 4 /* Size of each program header entry. */ -#define IMAGE_ELF_AUX_TYPE_PHNUM 5 /* Number of program header entries. */ -#define IMAGE_ELF_AUX_TYPE_PAGESZ 6 /* Page size in bytes. */ -#define IMAGE_ELF_AUX_TYPE_BASE 7 /* Interpreter's base address. */ -#define IMAGE_ELF_AUX_TYPE_FLAGS 8 /* Flags (unused for i386). */ -#define IMAGE_ELF_AUX_TYPE_ENTRY 9 /* Where interpreter should transfer control. */ +/* Machine-independent and word-size-independent definitions */ +#include /* - * The following non-standard values are used for passing information - * from John Polstra's testbed program to the dynamic linker. These - * are expected to go away soon. - * - * Unfortunately, these overlap the Linux non-standard values, so they - * must not be used in the same context. + * Word-size-dependent definitions. All ReactOS builds support all of them, + * even if (obviously) code for the wrong architecture cannot be executed - the + * files can still be used in machine-independent ways, e.g. as resource DLLs */ -#define IMAGE_ELF_AUX_TYPE_BRK 10 /* Starting point for sbrk and brk. */ -#define IMAGE_ELF_AUX_TYPE_DEBUG 11 /* Debugging level. */ +#include +#include -/* - * The following non-standard values are used in Linux ELF binaries. - */ -#define IMAGE_ELF_AUX_TYPE_NOTELF 10 /* Program is not ELF ?? */ -#define IMAGE_ELF_AUX_TYPE_UID 11 /* Real uid. */ -#define IMAGE_ELF_AUX_TYPE_EUID 12 /* Effective uid. */ -#define IMAGE_ELF_AUX_TYPE_GID 13 /* Real gid. */ -#define IMAGE_ELF_AUX_TYPE_EGID 14 /* Effective gid. */ +/* Machine-dependent definitions */ +#include -#define IMAGE_ELF_AUX_TYPE_COUNT 15 /* Count of defined aux entry types. */ - - -/* Auxiliary vector entry on initial stack */ -typedef struct _IMAGE_ELF32_AUXINFO { - ELF32_SWORD Type; /* Entry type. */ - union { - ELF32_SWORD Val; /* Integer value. */ - ELF32_ADDR Ptr; /* Address. */ - void (*Fcn)(void); /* Function pointer (not used). */ - } Un; -} IMAGE_ELF32_AUXINFO, *PIMAGE_ELF32_AUXINFO; - - - - - -/* arch data types */ - -#if ELF_ARCH_SIZE == 32 - -#define IMAGE_ELF_SYMBOL_BIND(args...) IMAGE_ELF32_SYMBOL_BIND(args) -#define IMAGE_ELF_SYMBOL_TYPE(args...) IMAGE_ELF32_SYMBOL_TYPE(args) -#define IMAGE_ELF_SYMBOL_INFO(args...) IMAGE_ELF32_SYMBOL_INFO(args) - -#define IMAGE_ELF_RELOC_SYM(args...) IMAGE_ELF32_RELOC_SYM(args) -#define IMAGE_ELF_RELOC_TYPE(args...) IMAGE_ELF32_RELOC_TYPE(args) -#define IMAGE_ELF_RELOC_INFO(args...) IMAGE_ELF32_RELOC_INFO(args) - -typedef ELF32_ADDR ELF_ADDR; -typedef ELF32_HALF ELF_HALF; -typedef ELF32_OFF ELF_OFF; -typedef ELF32_SWORD ELF_SWORD; -typedef ELF32_WORD ELF_WORD; -typedef ELF32_HASHELT ELF_HASHELT; - -typedef IMAGE_ELF32_HEADER IMAGE_ELF_HEADER, *PIMAGE_ELF_HEADER; -typedef IMAGE_ELF32_SECTION_HEADER IMAGE_ELF_SECTION_HEADER, *PIMAGE_ELF_SECTION_HEADER; -typedef IMAGE_ELF32_SYMBOL IMAGE_ELF_SYMBOL, *PIMAGE_ELF_SYMBOL; -typedef IMAGE_ELF32_RELOC IMAGE_ELF_RELOC, *PIMAGE_ELF_RELOC; -typedef IMAGE_ELF32_RELOCA IMAGE_ELF_RELOCA, *PIMAGE_ELF_RELOCA; -typedef IMAGE_ELF32_PROGRAM_HEADER IMAGE_ELF_PROGRAM_HEADER, *PIMAGE_ELF_PROGRAM_HEADER; -typedef IMAGE_ELF32_DYNAMIC IMAGE_ELF_DYNAMIC, *PIMAGE_ELF_DYNAMIC; -typedef IMAGE_ELF32_AUXINFO IMAGE_ELF_AUXINFO, *PIMAGE_ELF_AUXINFO; - -#elif ELF_ARCH_SIZE == 64 -# error 64 bits unsupported -#else -# error Undefined architecture size! #endif - - - -/* target macros */ -#ifdef _M_IX86 -# define IMAGE_ELF_TARGET_CLASS IMAGE_ELF_CLASS_32 -# define IMAGE_ELF_TARGET_DATA IMAGE_ELF_DATA_2LSB -# define IMAGE_ELF_TARGET_MACHINE IMAGE_ELF_MACHINE_386 -# define IMAGE_ELF_TARGET_VERSION 1 -#else -# error Unsupported architecture! -#endif - -#undef ELF_ARCH_SIZE - -#endif /* __INCLUDE_ELF_H */ - +/* EOF */ diff --git a/reactos/include/elf/common.h b/reactos/include/elf/common.h new file mode 100644 index 00000000000..1eb66ed6c27 --- /dev/null +++ b/reactos/include/elf/common.h @@ -0,0 +1,392 @@ +/*- + * Copyright (c) 1998 John D. Polstra. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/sys/elf_common.h,v 1.15 2004/05/05 02:38:54 marcel Exp $ + */ + +#ifndef _SYS_ELF_COMMON_H_ +#define _SYS_ELF_COMMON_H_ 1 + +/* + * ELF definitions that are independent of architecture or word size. + */ + +/* + * Note header. The ".note" section contains an array of notes. Each + * begins with this header, aligned to a word boundary. Immediately + * following the note header is n_namesz bytes of name, padded to the + * next word boundary. Then comes n_descsz bytes of descriptor, again + * padded to a word boundary. The values of n_namesz and n_descsz do + * not include the padding. + */ + +typedef struct { + UINT32 n_namesz; /* Length of name. */ + UINT32 n_descsz; /* Length of descriptor. */ + UINT32 n_type; /* Type of this note. */ +} Elf_Note; + +/* Indexes into the e_ident array. Keep synced with + http://www.sco.com/developer/gabi/ch4.eheader.html */ +#define EI_MAG0 0 /* Magic number, byte 0. */ +#define EI_MAG1 1 /* Magic number, byte 1. */ +#define EI_MAG2 2 /* Magic number, byte 2. */ +#define EI_MAG3 3 /* Magic number, byte 3. */ +#define EI_CLASS 4 /* Class of machine. */ +#define EI_DATA 5 /* Data format. */ +#define EI_VERSION 6 /* ELF format version. */ +#define EI_OSABI 7 /* Operating system / ABI identification */ +#define EI_ABIVERSION 8 /* ABI version */ +#define OLD_EI_BRAND 8 /* Start of architecture identification. */ +#define EI_PAD 9 /* Start of padding (per SVR4 ABI). */ +#define EI_NIDENT 16 /* Size of e_ident array. */ + +/* Values for the magic number bytes. */ +#define ELFMAG0 0x7f +#define ELFMAG1 'E' +#define ELFMAG2 'L' +#define ELFMAG3 'F' +#define ELFMAG "\177ELF" /* magic string */ +#define SELFMAG 4 /* magic string size */ + +/* Values for e_ident[EI_VERSION] and e_version. */ +#define EV_NONE 0 +#define EV_CURRENT 1 + +/* Values for e_ident[EI_CLASS]. */ +#define ELFCLASSNONE 0 /* Unknown class. */ +#define ELFCLASS32 1 /* 32-bit architecture. */ +#define ELFCLASS64 2 /* 64-bit architecture. */ + +/* Values for e_ident[EI_DATA]. */ +#define ELFDATANONE 0 /* Unknown data format. */ +#define ELFDATA2LSB 1 /* 2's complement little-endian. */ +#define ELFDATA2MSB 2 /* 2's complement big-endian. */ + +/* Values for e_ident[EI_OSABI]. */ +#define ELFOSABI_SYSV 0 /* UNIX System V ABI */ +#define ELFOSABI_NONE ELFOSABI_SYSV /* symbol used in old spec */ +#define ELFOSABI_HPUX 1 /* HP-UX operating system */ +#define ELFOSABI_NETBSD 2 /* NetBSD */ +#define ELFOSABI_LINUX 3 /* GNU/Linux */ +#define ELFOSABI_HURD 4 /* GNU/Hurd */ +#define ELFOSABI_86OPEN 5 /* 86Open common IA32 ABI */ +#define ELFOSABI_SOLARIS 6 /* Solaris */ +#define ELFOSABI_MONTEREY 7 /* Monterey */ +#define ELFOSABI_IRIX 8 /* IRIX */ +#define ELFOSABI_FREEBSD 9 /* FreeBSD */ +#define ELFOSABI_TRU64 10 /* TRU64 UNIX */ +#define ELFOSABI_MODESTO 11 /* Novell Modesto */ +#define ELFOSABI_OPENBSD 12 /* OpenBSD */ +#define ELFOSABI_ARM 97 /* ARM */ +#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ + +/* e_ident */ +#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \ + (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \ + (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \ + (ehdr).e_ident[EI_MAG3] == ELFMAG3) + +/* Values for e_type. */ +#define ET_NONE 0 /* Unknown type. */ +#define ET_REL 1 /* Relocatable. */ +#define ET_EXEC 2 /* Executable. */ +#define ET_DYN 3 /* Shared object. */ +#define ET_CORE 4 /* Core file. */ + +/* Values for e_machine. */ +/* + * Source: + * System V Application Binary Interface (DRAFT) 2003-12-17, Chapter 4, Section + * "ELF Header" + */ +#define EM_NONE 0 /* No machine */ +#define EM_M32 1 /* AT&T WE 32100 */ +#define EM_SPARC 2 /* SPARC */ +#define EM_386 3 /* Intel 80386 */ +#define EM_68K 4 /* Motorola 68000 */ +#define EM_88K 5 /* Motorola 88000 */ +/* reserved 6 Reserved for future use (was EM_486) */ +#define EM_860 7 /* Intel 80860 */ +#define EM_MIPS 8 /* MIPS I Architecture */ +#define EM_S370 9 /* IBM System/370 Processor */ +#define EM_MIPS_RS3_LE 10 /* MIPS RS3000 Little-endian */ +/* reserved 11-14 Reserved for future use */ +#define EM_PARISC 15 /* Hewlett-Packard PA-RISC */ +/* reserved 16 Reserved for future use */ +#define EM_VPP500 17 /* Fujitsu VPP500 */ +#define EM_SPARC32PLUS 18 /* Enhanced instruction set SPARC */ +#define EM_960 19 /* Intel 80960 */ +#define EM_PPC 20 /* PowerPC */ +#define EM_PPC64 21 /* 64-bit PowerPC */ +#define EM_S390 22 /* IBM System/390 Processor */ +/* reserved 23-35 Reserved for future use */ +#define EM_V800 36 /* NEC V800 */ +#define EM_FR20 37 /* Fujitsu FR20 */ +#define EM_RH32 38 /* TRW RH-32 */ +#define EM_RCE 39 /* Motorola RCE */ +#define EM_ARM 40 /* Advanced RISC Machines ARM */ +#define EM_ALPHA 41 /* Digital Alpha */ +#define EM_SH 42 /* Hitachi SH */ +#define EM_SPARCV9 43 /* SPARC Version 9 */ +#define EM_TRICORE 44 /* Siemens TriCore embedded processor */ +#define EM_ARC 45 /* Argonaut RISC Core, Argonaut Technologies + Inc. */ +#define EM_H8_300 46 /* Hitachi H8/300 */ +#define EM_H8_300H 47 /* Hitachi H8/300H */ +#define EM_H8S 48 /* Hitachi H8S */ +#define EM_H8_500 49 /* Hitachi H8/500 */ +#define EM_IA_64 50 /* Intel IA-64 processor architecture */ +#define EM_MIPS_X 51 /* Stanford MIPS-X */ +#define EM_COLDFIRE 52 /* Motorola ColdFire */ +#define EM_68HC12 53 /* Motorola M68HC12 */ +#define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator */ +#define EM_PCP 55 /* Siemens PCP */ +#define EM_NCPU 56 /* Sony nCPU embedded RISC processor */ +#define EM_NDR1 57 /* Denso NDR1 microprocessor */ +#define EM_STARCORE 58 /* Motorola Star*Core processor */ +#define EM_ME16 59 /* Toyota ME16 processor */ +#define EM_ST100 60 /* STMicroelectronics ST100 processor */ +#define EM_TINYJ 61 /* Advanced Logic Corp. TinyJ embedded processor + family */ +#define EM_X86_64 62 /* AMD x86-64 architecture */ +#define EM_PDSP 63 /* Sony DSP Processor */ +#define EM_PDP10 64 /* Digital Equipment Corp. PDP-10 */ +#define EM_PDP11 65 /* Digital Equipment Corp. PDP-11 */ +#define EM_FX66 66 /* Siemens FX66 microcontroller */ +#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 bit + microcontroller */ +#define EM_ST7 68 /* STMicroelectronics ST7 8-bit + microcontroller */ +#define EM_68HC16 69 /* Motorola MC68HC16 Microcontroller */ +#define EM_68HC11 70 /* Motorola MC68HC11 Microcontroller */ +#define EM_68HC08 71 /* Motorola MC68HC08 Microcontroller */ +#define EM_68HC05 72 /* Motorola MC68HC05 Microcontroller */ +#define EM_SVX 73 /* Silicon Graphics SVx */ +#define EM_ST19 74 /* STMicroelectronics ST19 8-bit + microcontroller */ +#define EM_VAX 75 /* Digital VAX */ +#define EM_CRIS 76 /* Axis Communications 32-bit embedded + processor */ +#define EM_JAVELIN 77 /* Infineon Technologies 32-bit embedded + processor */ +#define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */ +#define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */ +#define EM_MMIX 80 /* Donald Knuth's educational 64-bit + processor */ +#define EM_HUANY 81 /* Harvard University machine-independent object + files */ +#define EM_PRISM 82 /* SiTera Prism */ +#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */ +#define EM_FR30 84 /* Fujitsu FR30 */ +#define EM_D10V 85 /* Mitsubishi D10V */ +#define EM_D30V 86 /* Mitsubishi D30V */ +#define EM_V850 87 /* NEC v850 */ +#define EM_M32R 88 /* Mitsubishi M32R */ +#define EM_MN10300 89 /* Matsushita MN10300 */ +#define EM_MN10200 90 /* Matsushita MN10200 */ +#define EM_PJ 91 /* picoJava */ +#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */ +#define EM_ARC_A5 93 /* ARC Cores Tangent-A5 */ +#define EM_XTENSA 94 /* Tensilica Xtensa Architecture */ +#define EM_VIDEOCORE 95 /* Alphamosaic VideoCore processor */ +#define EM_TMM_GPP 96 /* Thompson Multimedia General Purpose + Processor */ +#define EM_NS32K 97 /* National Semiconductor 32000 series */ +#define EM_TPC 98 /* Tenor Network TPC processor */ +#define EM_SNP1K 99 /* Trebia SNP 1000 processor */ +#define EM_ST200 100 /* STMicroelectronics (www.st.com) ST200 + microcontroller */ +#define EM_IP2K 101 /* Ubicom IP2xxx microcontroller family */ +#define EM_MAX 102 /* MAX Processor */ +#define EM_CR 103 /* National Semiconductor CompactRISC + microprocessor */ +#define EM_F2MC16 104 /* Fujitsu F2MC16 */ +#define EM_MSP430 105 /* Texas Instruments embedded microcontroller + msp430 */ +#define EM_BLACKFIN 106 /* Analog Devices Blackfin (DSP) processor */ +#define EM_SE_C33 107 /* S1C33 Family of Seiko Epson processors */ +#define EM_SEP 108 /* Sharp embedded microprocessor */ +#define EM_ARCA 109 /* Arca RISC Microprocessor */ +#define EM_UNICORE 110 /* Microprocessor series from PKU-Unity Ltd. and + MPRC of Peking University */ + +/* Special section indexes. */ +#define SHN_UNDEF 0 /* Undefined, missing, irrelevant. */ +#define SHN_LORESERVE 0xff00 /* First of reserved range. */ +#define SHN_LOPROC 0xff00 /* First processor-specific. */ +#define SHN_HIPROC 0xff1f /* Last processor-specific. */ +#define SHN_ABS 0xfff1 /* Absolute values. */ +#define SHN_COMMON 0xfff2 /* Common data. */ +#define SHN_HIRESERVE 0xffff /* Last of reserved range. */ + +/* sh_type */ +#define SHT_NULL 0 /* inactive */ +#define SHT_PROGBITS 1 /* program defined information */ +#define SHT_SYMTAB 2 /* symbol table section */ +#define SHT_STRTAB 3 /* string table section */ +#define SHT_RELA 4 /* relocation section with addends */ +#define SHT_HASH 5 /* symbol hash table section */ +#define SHT_DYNAMIC 6 /* dynamic section */ +#define SHT_NOTE 7 /* note section */ +#define SHT_NOBITS 8 /* no space section */ +#define SHT_REL 9 /* relocation section - no addends */ +#define SHT_SHLIB 10 /* reserved - purpose unknown */ +#define SHT_DYNSYM 11 /* dynamic symbol table section */ +#define SHT_NUM 12 /* number of section types */ +#define SHT_LOOS 0x60000000 /* First of OS specific semantics */ +#define SHT_HIOS 0x6fffffff /* Last of OS specific semantics */ +#define SHT_LOPROC 0x70000000 /* reserved range for processor */ +#define SHT_HIPROC 0x7fffffff /* specific section header types */ +#define SHT_LOUSER 0x80000000 /* reserved range for application */ +#define SHT_HIUSER 0xffffffff /* specific indexes */ + +/* Flags for sh_flags. */ +#define SHF_WRITE 0x1 /* Section contains writable data. */ +#define SHF_ALLOC 0x2 /* Section occupies memory. */ +#define SHF_EXECINSTR 0x4 /* Section contains instructions. */ +#define SHF_TLS 0x400 /* Section contains TLS data. */ +#define SHF_MASKPROC 0xf0000000 /* Reserved for processor-specific. */ + +/* Values for p_type. */ +#define PT_NULL 0 /* Unused entry. */ +#define PT_LOAD 1 /* Loadable segment. */ +#define PT_DYNAMIC 2 /* Dynamic linking information segment. */ +#define PT_INTERP 3 /* Pathname of interpreter. */ +#define PT_NOTE 4 /* Auxiliary information. */ +#define PT_SHLIB 5 /* Reserved (not used). */ +#define PT_PHDR 6 /* Location of program header itself. */ +#define PT_TLS 7 /* Thread local storage segment */ + +#define PT_COUNT 8 /* Number of defined p_type values. */ + +#define PT_LOOS 0x60000000 /* OS-specific */ +#define PT_HIOS 0x6fffffff /* OS-specific */ +#define PT_LOPROC 0x70000000 /* First processor-specific type. */ +#define PT_HIPROC 0x7fffffff /* Last processor-specific type. */ + +/* Values for p_flags. */ +#define PF_X 0x1 /* Executable. */ +#define PF_W 0x2 /* Writable. */ +#define PF_R 0x4 /* Readable. */ + +/* Values for d_tag. */ +#define DT_NULL 0 /* Terminating entry. */ +#define DT_NEEDED 1 /* String table offset of a needed shared + library. */ +#define DT_PLTRELSZ 2 /* Total size in bytes of PLT relocations. */ +#define DT_PLTGOT 3 /* Processor-dependent address. */ +#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 ElfNN_Rela relocations. */ +#define DT_RELASZ 8 /* Total size of ElfNN_Rela relocations. */ +#define DT_RELAENT 9 /* Size of each ElfNN_Rela relocation entry. */ +#define DT_STRSZ 10 /* Size of string table. */ +#define DT_SYMENT 11 /* Size of each symbol table entry. */ +#define DT_INIT 12 /* Address of initialization function. */ +#define DT_FINI 13 /* Address of finalization function. */ +#define DT_SONAME 14 /* String table offset of shared object + name. */ +#define DT_RPATH 15 /* String table offset of library path. [sup] */ +#define DT_SYMBOLIC 16 /* Indicates "symbolic" linking. [sup] */ +#define DT_REL 17 /* Address of ElfNN_Rel relocations. */ +#define DT_RELSZ 18 /* Total size of ElfNN_Rel relocations. */ +#define DT_RELENT 19 /* Size of each ElfNN_Rel relocation. */ +#define DT_PLTREL 20 /* Type of relocation used for PLT. */ +#define DT_DEBUG 21 /* Reserved (not used). */ +#define DT_TEXTREL 22 /* Indicates there may be relocations in + non-writable segments. [sup] */ +#define DT_JMPREL 23 /* Address of PLT relocations. */ +#define DT_BIND_NOW 24 /* [sup] */ +#define DT_INIT_ARRAY 25 /* Address of the array of pointers to + initialization functions */ +#define DT_FINI_ARRAY 26 /* Address of the array of pointers to + termination functions */ +#define DT_INIT_ARRAYSZ 27 /* Size in bytes of the array of + initialization functions. */ +#define DT_FINI_ARRAYSZ 28 /* Size in bytes of the array of + terminationfunctions. */ +#define DT_RUNPATH 29 /* String table offset of a null-terminated + library search path string. */ +#define DT_FLAGS 30 /* Object specific flag values. */ +#define DT_ENCODING 32 /* Values greater than or equal to DT_ENCODING + and less than DT_LOOS follow the rules for + the interpretation of the d_un union + as follows: even == 'd_ptr', even == 'd_val' + or none */ +#define DT_PREINIT_ARRAY 32 /* Address of the array of pointers to + pre-initialization functions. */ +#define DT_PREINIT_ARRAYSZ 33 /* Size in bytes of the array of + pre-initialization functions. */ + +#define DT_COUNT 33 /* Number of defined d_tag values. */ + +#define DT_LOOS 0x6000000d /* First OS-specific */ +#define DT_HIOS 0x6fff0000 /* Last OS-specific */ +#define DT_LOPROC 0x70000000 /* First processor-specific type. */ +#define DT_HIPROC 0x7fffffff /* Last processor-specific type. */ + +/* Values for DT_FLAGS */ +#define DF_ORIGIN 0x0001 /* Indicates that the object being loaded may + make reference to the $ORIGIN substitution + string */ +#define DF_SYMBOLIC 0x0002 /* Indicates "symbolic" linking. */ +#define DF_TEXTREL 0x0004 /* Indicates there may be relocations in + non-writable segments. */ +#define DF_BIND_NOW 0x0008 /* Indicates that the dynamic linker should + process all relocations for the object + containing this entry before transferring + control to the program. */ +#define DF_STATIC_TLS 0x0010 /* Indicates that the shared object or + executable contains code using a static + thread-local storage scheme. */ + +/* Values for n_type. Used in core files. */ +#define NT_PRSTATUS 1 /* Process status. */ +#define NT_FPREGSET 2 /* Floating point registers. */ +#define NT_PRPSINFO 3 /* Process state info. */ + +/* Symbol Binding - ELFNN_ST_BIND - st_info */ +#define STB_LOCAL 0 /* Local symbol */ +#define STB_GLOBAL 1 /* Global symbol */ +#define STB_WEAK 2 /* like global - lower precedence */ +#define STB_LOPROC 13 /* reserved range for processor */ +#define STB_HIPROC 15 /* specific symbol bindings */ + +/* Symbol type - ELFNN_ST_TYPE - st_info */ +#define STT_NOTYPE 0 /* Unspecified type. */ +#define STT_OBJECT 1 /* Data object. */ +#define STT_FUNC 2 /* Function. */ +#define STT_SECTION 3 /* Section. */ +#define STT_FILE 4 /* Source file. */ +#define STT_TLS 6 /* TLS object. */ +#define STT_LOPROC 13 /* reserved range for processor */ +#define STT_HIPROC 15 /* specific symbol types */ + +/* Special symbol table indexes. */ +#define STN_UNDEF 0 /* Undefined symbol index. */ + +#endif /* !_SYS_ELF_COMMON_H_ */ diff --git a/reactos/include/elf/elf-i386.h b/reactos/include/elf/elf-i386.h new file mode 100644 index 00000000000..9cba591163d --- /dev/null +++ b/reactos/include/elf/elf-i386.h @@ -0,0 +1,153 @@ +/*- + * Copyright (c) 1996-1997 John D. Polstra. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/i386/include/elf.h,v 1.16 2004/08/02 19:12:17 dfr Exp $ + */ + +#ifndef _MACHINE_ELF_H_ +#define _MACHINE_ELF_H_ 1 + +/* + * ELF definitions for the i386 architecture. + */ + +#ifdef _REACTOS_ELF_MACHINE_IS_TARGET + +#ifndef __ELF_WORD_SIZE +#define __ELF_WORD_SIZE 32 /* Used by */ +#endif + +#include + +#define ELF_ARCH EM_386 + +#define ELF_MACHINE_OK(x) ((x) == EM_386 || (x) == EM_486) + +/* + * Auxiliary vector entries for passing information to the interpreter. + * + * The i386 supplement to the SVR4 ABI specification names this "auxv_t", + * but POSIX lays claim to all symbols ending with "_t". + */ + +typedef struct { /* Auxiliary vector entry on initial stack */ + int a_type; /* Entry type. */ + union { + long a_val; /* Integer value. */ + void *a_ptr; /* Address. */ + void (*a_fcn)(void); /* Function pointer (not used). */ + } a_un; +} Elf32_Auxinfo; + +#if __ELF_WORD_SIZE == 64 +/* Fake for amd64 loader support */ +typedef struct { + int fake; +} Elf64_Auxinfo; +#endif + +__ElfType(Auxinfo); + +/* Values for a_type. */ +#define AT_NULL 0 /* Terminates the vector. */ +#define AT_IGNORE 1 /* Ignored entry. */ +#define AT_EXECFD 2 /* File descriptor of program to load. */ +#define AT_PHDR 3 /* Program header of program already loaded. */ +#define AT_PHENT 4 /* Size of each program header entry. */ +#define AT_PHNUM 5 /* Number of program header entries. */ +#define AT_PAGESZ 6 /* Page size in bytes. */ +#define AT_BASE 7 /* Interpreter's base address. */ +#define AT_FLAGS 8 /* Flags (unused for i386). */ +#define AT_ENTRY 9 /* Where interpreter should transfer control. */ + +/* + * The following non-standard values are used for passing information + * from John Polstra's testbed program to the dynamic linker. These + * are expected to go away soon. + * + * Unfortunately, these overlap the Linux non-standard values, so they + * must not be used in the same context. + */ +#define AT_BRK 10 /* Starting point for sbrk and brk. */ +#define AT_DEBUG 11 /* Debugging level. */ + +/* + * The following non-standard values are used in Linux ELF binaries. + */ +#define AT_NOTELF 10 /* Program is not ELF ?? */ +#define AT_UID 11 /* Real uid. */ +#define AT_EUID 12 /* Effective uid. */ +#define AT_GID 13 /* Real gid. */ +#define AT_EGID 14 /* Effective gid. */ + +#define AT_COUNT 15 /* Count of defined aux entry types. */ + +/* Define "machine" characteristics */ +#define ELF_TARG_CLASS ELFCLASS32 +#define ELF_TARG_DATA ELFDATA2LSB +#define ELF_TARG_MACH EM_386 +#define ELF_TARG_VER 1 + +#endif /* _REACTOS_ELF_MACHINE_IS_TARGET */ + +/* + * Relocation types. + */ + +#define R_386_NONE 0 /* No relocation. */ +#define R_386_32 1 /* Add symbol value. */ +#define R_386_PC32 2 /* Add PC-relative symbol value. */ +#define R_386_GOT32 3 /* Add PC-relative GOT offset. */ +#define R_386_PLT32 4 /* Add PC-relative PLT offset. */ +#define R_386_COPY 5 /* Copy data from shared object. */ +#define R_386_GLOB_DAT 6 /* Set GOT entry to data address. */ +#define R_386_JMP_SLOT 7 /* Set GOT entry to code address. */ +#define R_386_RELATIVE 8 /* Add load address of shared object. */ +#define R_386_GOTOFF 9 /* Add GOT-relative symbol address. */ +#define R_386_GOTPC 10 /* Add PC-relative GOT table address. */ +#define R_386_TLS_TPOFF 14 /* Negative offset in static TLS block */ +#define R_386_TLS_IE 15 /* Absolute address of GOT for -ve static TLS */ +#define R_386_TLS_GOTIE 16 /* GOT entry for negative static TLS block */ +#define R_386_TLS_LE 17 /* Negative offset relative to static TLS */ +#define R_386_TLS_GD 18 /* 32 bit offset to GOT (index,off) pair */ +#define R_386_TLS_LDM 19 /* 32 bit offset to GOT (index,zero) pair */ +#define R_386_TLS_GD_32 24 /* 32 bit offset to GOT (index,off) pair */ +#define R_386_TLS_GD_PUSH 25 /* pushl instruction for Sun ABI GD sequence */ +#define R_386_TLS_GD_CALL 26 /* call instruction for Sun ABI GD sequence */ +#define R_386_TLS_GD_POP 27 /* popl instruction for Sun ABI GD sequence */ +#define R_386_TLS_LDM_32 28 /* 32 bit offset to GOT (index,zero) pair */ +#define R_386_TLS_LDM_PUSH 29 /* pushl instruction for Sun ABI LD sequence */ +#define R_386_TLS_LDM_CALL 30 /* call instruction for Sun ABI LD sequence */ +#define R_386_TLS_LDM_POP 31 /* popl instruction for Sun ABI LD sequence */ +#define R_386_TLS_LDO_32 32 /* 32 bit offset from start of TLS block */ +#define R_386_TLS_IE_32 33 /* 32 bit offset to GOT static TLS offset entry */ +#define R_386_TLS_LE_32 34 /* 32 bit offset within static TLS block */ +#define R_386_TLS_DTPMOD32 35 /* GOT entry containing TLS index */ +#define R_386_TLS_DTPOFF32 36 /* GOT entry containing TLS offset */ +#define R_386_TLS_TPOFF32 37 /* GOT entry of -ve static TLS offset */ + +#define R_386_COUNT 38 /* Count of defined relocation types. */ + +#endif /* !_MACHINE_ELF_H_ */ diff --git a/reactos/include/elf/elf32.h b/reactos/include/elf/elf32.h new file mode 100644 index 00000000000..9073e4c6236 --- /dev/null +++ b/reactos/include/elf/elf32.h @@ -0,0 +1,154 @@ +/*- + * Copyright (c) 1996-1998 John D. Polstra. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/sys/elf32.h,v 1.8 2002/05/30 08:32:18 dfr Exp $ + */ + +#ifndef _SYS_ELF32_H_ +#define _SYS_ELF32_H_ 1 + +/* + * ELF definitions common to all 32-bit architectures. + */ + +typedef ULONG32 Elf32_Addr; +typedef USHORT Elf32_Half; +typedef ULONG32 Elf32_Off; +typedef LONG32 Elf32_Sword; +typedef ULONG32 Elf32_Word; +typedef ULONG32 Elf32_Size; +typedef Elf32_Off Elf32_Hashelt; + +/* + * ELF header. + */ + +typedef struct { + unsigned char e_ident[EI_NIDENT]; /* File identification. */ + Elf32_Half e_type; /* File type. */ + Elf32_Half e_machine; /* Machine architecture. */ + Elf32_Word e_version; /* ELF format version. */ + Elf32_Addr e_entry; /* Entry point. */ + Elf32_Off e_phoff; /* Program header file offset. */ + Elf32_Off e_shoff; /* Section header file offset. */ + Elf32_Word e_flags; /* Architecture-specific flags. */ + Elf32_Half e_ehsize; /* Size of ELF header in bytes. */ + Elf32_Half e_phentsize; /* Size of program header entry. */ + Elf32_Half e_phnum; /* Number of program header entries. */ + Elf32_Half e_shentsize; /* Size of section header entry. */ + Elf32_Half e_shnum; /* Number of section header entries. */ + Elf32_Half e_shstrndx; /* Section name strings section. */ +} Elf32_Ehdr; + +/* + * Section header. + */ + +typedef struct { + Elf32_Word sh_name; /* Section name (index into the + section header string table). */ + Elf32_Word sh_type; /* Section type. */ + Elf32_Word sh_flags; /* Section flags. */ + Elf32_Addr sh_addr; /* Address in memory image. */ + Elf32_Off sh_offset; /* Offset in file. */ + Elf32_Size sh_size; /* Size in bytes. */ + Elf32_Word sh_link; /* Index of a related section. */ + Elf32_Word sh_info; /* Depends on section type. */ + Elf32_Size sh_addralign; /* Alignment in bytes. */ + Elf32_Size sh_entsize; /* Size of each entry in section. */ +} Elf32_Shdr; + +/* + * Program header. + */ + +typedef struct { + Elf32_Word p_type; /* Entry type. */ + Elf32_Off p_offset; /* File offset of contents. */ + Elf32_Addr p_vaddr; /* Virtual address in memory image. */ + Elf32_Addr p_paddr; /* Physical address (not used). */ + Elf32_Size p_filesz; /* Size of contents in file. */ + Elf32_Size p_memsz; /* Size of contents in memory. */ + Elf32_Word p_flags; /* Access permission flags. */ + Elf32_Size p_align; /* Alignment in memory and file. */ +} Elf32_Phdr; + +/* + * Dynamic structure. The ".dynamic" section contains an array of them. + */ + +typedef struct { + Elf32_Sword d_tag; /* Entry type. */ + union { + Elf32_Size d_val; /* Integer value. */ + Elf32_Addr d_ptr; /* Address value. */ + } d_un; +} Elf32_Dyn; + +/* + * Relocation entries. + */ + +/* Relocations that don't need an addend field. */ +typedef struct { + Elf32_Addr r_offset; /* Location to be relocated. */ + Elf32_Word r_info; /* Relocation type and symbol index. */ +} Elf32_Rel; + +/* Relocations that need an addend field. */ +typedef struct { + Elf32_Addr r_offset; /* Location to be relocated. */ + Elf32_Word r_info; /* Relocation type and symbol index. */ + Elf32_Sword r_addend; /* Addend. */ +} Elf32_Rela; + +/* Macros for accessing the fields of r_info. */ +#define ELF32_R_SYM(info) ((info) >> 8) +#define ELF32_R_TYPE(info) ((unsigned char)(info)) + +/* Macro for constructing r_info from field values. */ +#define ELF32_R_INFO(sym, type) (((sym) << 8) + (unsigned char)(type)) + +/* + * Symbol table entries. + */ + +typedef struct { + Elf32_Word st_name; /* String table index of name. */ + Elf32_Addr st_value; /* Symbol value. */ + Elf32_Size st_size; /* Size of associated object. */ + unsigned char st_info; /* Type and binding information. */ + unsigned char st_other; /* Reserved (not used). */ + Elf32_Half st_shndx; /* Section index of symbol. */ +} Elf32_Sym; + +/* Macros for accessing the fields of st_info. */ +#define ELF32_ST_BIND(info) ((info) >> 4) +#define ELF32_ST_TYPE(info) ((info) & 0xf) + +/* Macro for constructing st_info from field values. */ +#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) + +#endif /* !_SYS_ELF32_H_ */ diff --git a/reactos/include/elf/elf64.h b/reactos/include/elf/elf64.h new file mode 100644 index 00000000000..9d535c0e847 --- /dev/null +++ b/reactos/include/elf/elf64.h @@ -0,0 +1,167 @@ +/*- + * Copyright (c) 1996-1998 John D. Polstra. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/sys/elf64.h,v 1.10 2002/05/30 08:32:18 dfr Exp $ + */ + +#ifndef _SYS_ELF64_H_ +#define _SYS_ELF64_H_ 1 + +/* + * ELF definitions common to all 64-bit architectures. + */ + +typedef ULONG64 Elf64_Addr; +typedef ULONG32 Elf64_Half; +typedef ULONG64 Elf64_Off; +typedef LONG64 Elf64_Sword; +typedef ULONG64 Elf64_Word; +typedef ULONG64 Elf64_Size; +typedef USHORT Elf64_Quarter; + +/* + * Types of dynamic symbol hash table bucket and chain elements. + * + * This is inconsistent among 64 bit architectures, so a machine dependent + * typedef is required. + */ + +#ifdef _ALPHA_ +typedef Elf64_Off Elf64_Hashelt; +#else +typedef Elf64_Half Elf64_Hashelt; +#endif + +/* + * ELF header. + */ + +typedef struct { + unsigned char e_ident[EI_NIDENT]; /* File identification. */ + Elf64_Quarter e_type; /* File type. */ + Elf64_Quarter e_machine; /* Machine architecture. */ + Elf64_Half e_version; /* ELF format version. */ + Elf64_Addr e_entry; /* Entry point. */ + Elf64_Off e_phoff; /* Program header file offset. */ + Elf64_Off e_shoff; /* Section header file offset. */ + Elf64_Half e_flags; /* Architecture-specific flags. */ + Elf64_Quarter e_ehsize; /* Size of ELF header in bytes. */ + Elf64_Quarter e_phentsize; /* Size of program header entry. */ + Elf64_Quarter e_phnum; /* Number of program header entries. */ + Elf64_Quarter e_shentsize; /* Size of section header entry. */ + Elf64_Quarter e_shnum; /* Number of section header entries. */ + Elf64_Quarter e_shstrndx; /* Section name strings section. */ +} Elf64_Ehdr; + +/* + * Section header. + */ + +typedef struct { + Elf64_Half sh_name; /* Section name (index into the + section header string table). */ + Elf64_Half sh_type; /* Section type. */ + Elf64_Size sh_flags; /* Section flags. */ + Elf64_Addr sh_addr; /* Address in memory image. */ + Elf64_Off sh_offset; /* Offset in file. */ + Elf64_Size sh_size; /* Size in bytes. */ + Elf64_Half sh_link; /* Index of a related section. */ + Elf64_Half sh_info; /* Depends on section type. */ + Elf64_Size sh_addralign; /* Alignment in bytes. */ + Elf64_Size sh_entsize; /* Size of each entry in section. */ +} Elf64_Shdr; + +/* + * Program header. + */ + +typedef struct { + Elf64_Half p_type; /* Entry type. */ + Elf64_Half p_flags; /* Access permission flags. */ + Elf64_Off p_offset; /* File offset of contents. */ + Elf64_Addr p_vaddr; /* Virtual address in memory image. */ + Elf64_Addr p_paddr; /* Physical address (not used). */ + Elf64_Size p_filesz; /* Size of contents in file. */ + Elf64_Size p_memsz; /* Size of contents in memory. */ + Elf64_Size p_align; /* Alignment in memory and file. */ +} Elf64_Phdr; + +/* + * Dynamic structure. The ".dynamic" section contains an array of them. + */ + +typedef struct { + Elf64_Size d_tag; /* Entry type. */ + union { + Elf64_Size d_val; /* Integer value. */ + Elf64_Addr d_ptr; /* Address value. */ + } d_un; +} Elf64_Dyn; + +/* + * Relocation entries. + */ + +/* Relocations that don't need an addend field. */ +typedef struct { + Elf64_Addr r_offset; /* Location to be relocated. */ + Elf64_Size r_info; /* Relocation type and symbol index. */ +} Elf64_Rel; + +/* Relocations that need an addend field. */ +typedef struct { + Elf64_Addr r_offset; /* Location to be relocated. */ + Elf64_Size r_info; /* Relocation type and symbol index. */ + Elf64_Off r_addend; /* Addend. */ +} Elf64_Rela; + +/* Macros for accessing the fields of r_info. */ +#define ELF64_R_SYM(info) ((info) >> 32) +#define ELF64_R_TYPE(info) ((unsigned char)(info)) + +/* Macro for constructing r_info from field values. */ +#define ELF64_R_INFO(sym, type) (((sym) << 32) + (unsigned char)(type)) + +/* + * Symbol table entries. + */ + +typedef struct { + Elf64_Half st_name; /* String table index of name. */ + unsigned char st_info; /* Type and binding information. */ + unsigned char st_other; /* Reserved (not used). */ + Elf64_Quarter st_shndx; /* Section index of symbol. */ + Elf64_Addr st_value; /* Symbol value. */ + Elf64_Size st_size; /* Size of associated object. */ +} Elf64_Sym; + +/* Macros for accessing the fields of st_info. */ +#define ELF64_ST_BIND(info) ((info) >> 4) +#define ELF64_ST_TYPE(info) ((info) & 0xf) + +/* Macro for constructing st_info from field values. */ +#define ELF64_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) + +#endif /* !_SYS_ELF64_H_ */ diff --git a/reactos/include/elf/generic.h b/reactos/include/elf/generic.h new file mode 100644 index 00000000000..6134f817923 --- /dev/null +++ b/reactos/include/elf/generic.h @@ -0,0 +1,87 @@ +/*- + * Copyright (c) 1998 John D. Polstra. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/sys/elf_generic.h,v 1.6 2002/07/20 02:56:11 peter Exp $ + */ + +#ifndef _SYS_ELF_GENERIC_H_ +#define _SYS_ELF_GENERIC_H_ 1 + +/* [REACTOS] TODO: we need to define this somewhere global */ +#define __ELF_CONCAT1(x,y) x ## y +#define __ELF_CONCAT(x,y) __ELF_CONCAT1(x,y) + +/* + * Definitions of generic ELF names which relieve applications from + * needing to know the word size. + */ + +#if __ELF_WORD_SIZE != 32 && __ELF_WORD_SIZE != 64 +#error "__ELF_WORD_SIZE must be defined as 32 or 64" +#endif + +#define ELF_CLASS __ELF_CONCAT(ELFCLASS,__ELF_WORD_SIZE) + +#if 0 +#if BYTE_ORDER == LITTLE_ENDIAN +#define ELF_DATA ELFDATA2LSB +#elif BYTE_ORDER == BIG_ENDIAN +#define ELF_DATA ELFDATA2MSB +#else +#error "Unknown byte order" +#endif +#else +/* [REACTOS] FIXME: we need to add this to our build system */ +#define ELF_DATA ELFDATA2LSB +#endif + +#define __elfN(x) __ELF_CONCAT(__ELF_CONCAT(__ELF_CONCAT(elf,__ELF_WORD_SIZE),_),x) +#define __ElfN(x) __ELF_CONCAT(__ELF_CONCAT(__ELF_CONCAT(Elf,__ELF_WORD_SIZE),_),x) +#define __ELFN(x) __ELF_CONCAT(__ELF_CONCAT(__ELF_CONCAT(ELF,__ELF_WORD_SIZE),_),x) +#define __ElfType(x) typedef __ElfN(x) __ELF_CONCAT(Elf_,x) + +__ElfType(Addr); +__ElfType(Half); +__ElfType(Off); +__ElfType(Sword); +__ElfType(Word); +__ElfType(Size); +__ElfType(Hashelt); +__ElfType(Ehdr); +__ElfType(Shdr); +__ElfType(Phdr); +__ElfType(Dyn); +__ElfType(Rel); +__ElfType(Rela); +__ElfType(Sym); + +#define ELF_R_SYM __ELFN(R_SYM) +#define ELF_R_TYPE __ELFN(R_TYPE) +#define ELF_R_INFO __ELFN(R_INFO) +#define ELF_ST_BIND __ELFN(ST_BIND) +#define ELF_ST_TYPE __ELFN(ST_TYPE) +#define ELF_ST_INFO __ELFN(ST_INFO) + +#endif /* !_SYS_ELF_GENERIC_H_ */ diff --git a/reactos/include/elf/machine.h b/reactos/include/elf/machine.h new file mode 100644 index 00000000000..27d7e494ebd --- /dev/null +++ b/reactos/include/elf/machine.h @@ -0,0 +1,12 @@ +#ifndef _REACTOS_ELF_MACHINE_H_ +#define _REACTOS_ELF_MACHINE_H_ 1 + +#ifdef _M_IX86 +#define _REACTOS_ELF_MACHINE_IS_TARGET +#include +#undef _REACTOS_ELF_MACHINE_IS_TARGET +#else +#error Unsupported target architecture +#endif + +#endif diff --git a/reactos/include/pe.h b/reactos/include/pe.h index 04c3f179c5d..105f4bef2e5 100644 --- a/reactos/include/pe.h +++ b/reactos/include/pe.h @@ -40,6 +40,7 @@ #define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 // File is executable (i.e. no unresolved externel references). #define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 // Line nunbers stripped from file. #define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 // Local symbols stripped from file. +#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 // Application supports addresses >2GB #define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 // Bytes of machine word are reversed. #define IMAGE_FILE_32BIT_MACHINE 0x0100 // 32 bit word machine. #define IMAGE_FILE_DEBUG_STRIPPED 0x0200 // Debugging info stripped from file in .DBG file @@ -57,6 +58,12 @@ #define IMAGE_FILE_MACHINE_R10000 0x168 // MIPS little-endian #define IMAGE_FILE_MACHINE_ALPHA 0x184 // Alpha_AXP #define IMAGE_FILE_MACHINE_POWERPC 0x1F0 // IBM PowerPC Little-Endian +#define IMAGE_FILE_MACHINE_ARM 0x01c0 // ARM little-endian +#define IMAGE_FILE_MACHINE_IA64 0x0200 // Intel IA64 +#define IMAGE_FILE_MACHINE_AXP64 IMAGE_FILE_MACHINE_ALPHA64 +#define IMAGE_FILE_MACHINE_ALPHA64 0x0284 // Alpha AXP, full 64-bit support +#define IMAGE_FILE_MACHINE_AMD64 0x8664 // AMD x86-64 +#define IMAGE_FILE_MACHINE_M32R 0x9041 // M32R little-endian #pragma pack(push,4) typedef struct _IMAGE_FILE_HEADER { @@ -104,7 +111,46 @@ typedef struct _IMAGE_OPTIONAL_HEADER { DWORD LoaderFlags; DWORD NumberOfRvaAndSizes; IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; -} IMAGE_OPTIONAL_HEADER,*PIMAGE_OPTIONAL_HEADER; +} IMAGE_OPTIONAL_HEADER32,*PIMAGE_OPTIONAL_HEADER32; +typedef struct _IMAGE_OPTIONAL_HEADER64 { + WORD Magic; + BYTE MajorLinkerVersion; + BYTE MinorLinkerVersion; + DWORD SizeOfCode; + DWORD SizeOfInitializedData; + DWORD SizeOfUninitializedData; + DWORD AddressOfEntryPoint; + DWORD BaseOfCode; + ULONGLONG ImageBase; + DWORD SectionAlignment; + DWORD FileAlignment; + WORD MajorOperatingSystemVersion; + WORD MinorOperatingSystemVersion; + WORD MajorImageVersion; + WORD MinorImageVersion; + WORD MajorSubsystemVersion; + WORD MinorSubsystemVersion; + DWORD Reserved1; + DWORD SizeOfImage; + DWORD SizeOfHeaders; + DWORD CheckSum; + WORD Subsystem; + WORD DllCharacteristics; + ULONGLONG SizeOfStackReserve; + ULONGLONG SizeOfStackCommit; + ULONGLONG SizeOfHeapReserve; + ULONGLONG SizeOfHeapCommit; + DWORD LoaderFlags; + DWORD NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; +} IMAGE_OPTIONAL_HEADER64,*PIMAGE_OPTIONAL_HEADER64; +#ifdef _WIN64 +typedef IMAGE_OPTIONAL_HEADER64 IMAGE_OPTIONAL_HEADER; +typedef PIMAGE_OPTIONAL_HEADER64 PIMAGE_OPTIONAL_HEADER; +#else +typedef IMAGE_OPTIONAL_HEADER32 IMAGE_OPTIONAL_HEADER; +typedef PIMAGE_OPTIONAL_HEADER32 PIMAGE_OPTIONAL_HEADER; +#endif typedef struct _IMAGE_ROM_OPTIONAL_HEADER { WORD Magic; BYTE MajorLinkerVersion; @@ -180,8 +226,20 @@ typedef struct _IMAGE_OS2_HEADER { typedef struct _IMAGE_NT_HEADERS { DWORD Signature; IMAGE_FILE_HEADER FileHeader; - IMAGE_OPTIONAL_HEADER OptionalHeader; -} IMAGE_NT_HEADERS,*PIMAGE_NT_HEADERS; + IMAGE_OPTIONAL_HEADER32 OptionalHeader; +} IMAGE_NT_HEADERS32,*PIMAGE_NT_HEADERS32; +typedef struct _IMAGE_NT_HEADERS64 { + DWORD Signature; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER64 OptionalHeader; +} IMAGE_NT_HEADERS64,*PIMAGE_NT_HEADERS64; +#ifdef _WIN64 +typedef IMAGE_NT_HEADERS64 IMAGE_NT_HEADERS; +typedef PIMAGE_NT_HEADERS64 PIMAGE_NT_HEADERS; +#else +typedef IMAGE_NT_HEADERS32 IMAGE_NT_HEADERS; +typedef PIMAGE_NT_HEADERS32 PIMAGE_NT_HEADERS; +#endif typedef struct _IMAGE_ROM_HEADERS { IMAGE_FILE_HEADER FileHeader; IMAGE_ROM_OPTIONAL_HEADER OptionalHeader; @@ -494,6 +552,12 @@ typedef struct _IMAGE_RESOURCE_DIRECTORY { } IMAGE_RESOURCE_DIRECTORY, *PIMAGE_RESOURCE_DIRECTORY; */ +#ifdef _WIN64 +#define IMAGE_NT_OPTIONAL_HDR_MAGIC IMAGE_NT_OPTIONAL_HDR64_MAGIC +#else +#define IMAGE_NT_OPTIONAL_HDR_MAGIC IMAGE_NT_OPTIONAL_HDR32_MAGIC +#endif + #endif /* !__USE_W32API */ #define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S)) @@ -555,7 +619,8 @@ typedef struct _IMAGE_RESOURCE_DIRECTORY { #define IMAGE_SIZEOF_FILE_HEADER 20 #define IMAGE_FILE_MACHINE_UNKNOWN 0 #define IMAGE_NT_SIGNATURE 0x00004550 -#define IMAGE_NT_OPTIONAL_HDR_MAGIC 0x10b +#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b +#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b #define IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x107 #define IMAGE_SEPARATE_DEBUG_SIGNATURE 0x4944 #define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 diff --git a/reactos/include/pseh.h b/reactos/include/pseh.h index ac9eb500aa4..9535555ef4e 100644 --- a/reactos/include/pseh.h +++ b/reactos/include/pseh.h @@ -23,6 +23,50 @@ #ifndef KJK_PSEH_H_ #define KJK_PSEH_H_ +/* Some useful macros */ +#if defined(__cplusplus) +# define _SEH_PVOID_CAST(TYPE_, P_) ((TYPE_)(P_)) +#else +# define _SEH_PVOID_CAST(TYPE_, P_) (P_) +#endif + +#if defined(FIELD_OFFSET) +# define _SEH_FIELD_OFFSET FIELD_OFFSET +#else +# include +# define _SEH_FIELD_OFFSET offsetof +#endif + +#if defined(CONTAINING_RECORD) +# define _SEH_CONTAINING_RECORD CONTAINING_RECORD +#else +# define _SEH_CONTAINING_RECORD(ADDR_, TYPE_, FIELD_) \ + ((TYPE_ *)(((char *)(ADDR_)) - _SEH_FIELD_OFFSET(TYPE_, FIELD_))) +#endif + +#if defined(__CONCAT) +# define _SEH_CONCAT __CONCAT +#else +# define _SEH_CONCAT1(X_, Y_) X_ ## Y_ +# define _SEH_CONCAT(X_, Y_) _SEH_CONCAT1(X_, Y_) +#endif + +/* Locals sharing support */ +#define _SEH_LOCALS_TYPENAME(BASENAME_) \ + struct _SEH_CONCAT(_SEHLocalsTag, BASENAME_) + +#define _SEH_DEFINE_LOCALS(BASENAME_) \ + _SEH_LOCALS_TYPENAME(BASENAME_) + +#define _SEH_DECLARE_LOCALS(BASENAME_) \ + _SEH_LOCALS_TYPENAME(BASENAME_) _SEHLocals; \ + _SEH_LOCALS_TYPENAME(BASENAME_) * _SEHPLocals; \ + _SEHPLocals = &_SEHLocals; + +/* Dummy locals */ +static _SEH_LOCALS_TYPENAME(_SEHDummyLocals) { int Dummy_; } _SEHLocals; +static void __inline _SEHDummyLocalsUser(void) { (void)_SEHLocals; } + /* TODO: to wrap native SEH implementations */ #include diff --git a/reactos/include/pseh/framebased.h b/reactos/include/pseh/framebased.h index 063fc7dd5f6..8a913c6435e 100644 --- a/reactos/include/pseh/framebased.h +++ b/reactos/include/pseh/framebased.h @@ -72,21 +72,66 @@ static __declspec(noreturn) __inline void __stdcall _SEHCompilerSpecificHandler _SEHLongJmp(myframe->SEH_JmpBuf, 1); } +/* SHARED LOCALS */ +/* Access the locals for the current frame */ +#define _SEH_ACCESS_LOCALS(LOCALS_) \ + _SEH_LOCALS_TYPENAME(LOCALS_) * _SEHPLocals; \ + _SEHPLocals = \ + _SEH_PVOID_CAST \ + ( \ + _SEH_LOCALS_TYPENAME(LOCALS_) *, \ + _SEH_CONTAINING_RECORD(_SEHPortableFrame, _SEHFrame_t, SEH_Header) \ + ->SEH_Locals \ + ); + +/* Access local variable VAR_ */ +#define _SEH_VAR(VAR_) _SEHPLocals->VAR_ + +/* FILTER FUNCTIONS */ +/* Declares a filter function's prototype */ #define _SEH_FILTER(NAME_) \ - int __stdcall NAME_ \ + long __stdcall NAME_ \ ( \ struct _EXCEPTION_POINTERS * _SEHExceptionPointers, \ struct __SEHPortableFrame * _SEHPortableFrame \ ) +/* Declares a static filter */ #define _SEH_STATIC_FILTER(ACTION_) ((_SEHFilter_t)((ACTION_) + 2)) +/* Declares a PSEH filter wrapping a regular filter function */ +#define _SEH_WRAP_FILTER(WRAPPER_, NAME_) \ + static __inline _SEH_FILTER(WRAPPER_) \ + { \ + return (NAME_)(_SEHExceptionPointers); \ + } + +/* FINALLY FUNCTIONS */ +/* Declares a finally function's prototype */ #define _SEH_FINALLY(NAME_) \ void __stdcall NAME_ \ ( \ struct __SEHPortableFrame * _SEHPortableFrame \ ) +/* Declares a PSEH finally function wrapping a regular function */ +#define _SEH_WRAP_FINALLY(WRAPPER_, NAME_) \ + _SEH_WRAP_FINALLY_ARGS(WRAPPER_, NAME_, ()) + +#define _SEH_WRAP_FINALLY_ARGS(WRAPPER_, NAME_, ARGS_) \ + static __inline _SEH_FINALLY(WRAPPER_) \ + { \ + NAME_ ARGS_; \ + } + +#define _SEH_WRAP_FINALLY_LOCALS_ARGS(WRAPPER_, LOCALS_, NAME_, ARGS_) \ + static __inline _SEH_FINALLY(WRAPPER_) \ + { \ + _SEH_ACCESS_LOCALS(LOCALS_); \ + NAME_ ARGS_; \ + } + +/* SAFE BLOCKS */ #define _SEH_TRY_FINALLY(FINALLY_) \ _SEH_TRY_FILTER_FINALLY \ ( \ @@ -109,22 +154,36 @@ static __declspec(noreturn) __inline void __stdcall _SEHCompilerSpecificHandler #define _SEH_TRY \ _SEH_TRY_HANDLE_FINALLY(NULL) +#ifdef __cplusplus +# define _SEH_DECLARE_HANDLERS(FILTER_, FINALLY_) \ + const _SEHHandlers_t _SEHHandlers = \ + { \ + (FILTER_), \ + _SEHCompilerSpecificHandler, \ + (FINALLY_) \ + }; +#else +# define _SEH_DECLARE_HANDLERS(FILTER_, FINALLY_) \ + _SEHHandlers_t _SEHHandlers = \ + { \ + (0), \ + _SEHCompilerSpecificHandler, \ + (0) \ + }; \ + _SEHHandlers.SH_Filter = (FILTER_); \ + _SEHHandlers.SH_Finally = (FINALLY_); +#endif + #define _SEH_TRY_FILTER_FINALLY(FILTER_, FINALLY_) \ { \ - static _SEHHandlers_t _SEHHandlers = \ - { \ - (NULL), \ - _SEHCompilerSpecificHandler, \ - (NULL) \ - }; \ - _SEHHandlers.SH_Filter = FILTER_; \ - _SEHHandlers.SH_Finally = FINALLY_; \ + _SEH_DECLARE_HANDLERS(FILTER_, FINALLY_); \ \ _SEHFrame_t * _SEHFrame; \ volatile _SEHPortableFrame_t * _SEHPortableFrame; \ \ _SEHFrame = _alloca(sizeof(_SEHFrame_t)); \ _SEHFrame->SEH_Header.SPF_Handlers = &_SEHHandlers; \ + _SEHFrame->SEH_Locals = &_SEHLocals; \ \ _SEHPortableFrame = &_SEHFrame->SEH_Header; \ (void)_SEHPortableFrame; \ diff --git a/reactos/include/pseh/framebased/internal.h b/reactos/include/pseh/framebased/internal.h index 5f7e76645ac..4c5f9169cab 100644 --- a/reactos/include/pseh/framebased/internal.h +++ b/reactos/include/pseh/framebased/internal.h @@ -44,7 +44,7 @@ _SEHRegistration_t; struct __SEHPortableFrame; -typedef int (__stdcall * _SEHFilter_t) +typedef long (__stdcall * _SEHFilter_t) ( struct _EXCEPTION_POINTERS *, struct __SEHPortableFrame * diff --git a/reactos/include/reactos/exeformat.h b/reactos/include/reactos/exeformat.h new file mode 100644 index 00000000000..f6f7b0c64bc --- /dev/null +++ b/reactos/include/reactos/exeformat.h @@ -0,0 +1,100 @@ +#ifndef REACTOS_EXEFORMAT_H_INCLUDED_ +#define REACTOS_EXEFORMAT_H_INCLUDED_ 1 + +/* + * LOADER API + */ +/* OUT flags returned by a loader */ +#define EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED (1 << 0) +#define EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP (1 << 1) +#define EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED (1 << 2) + +#define EXEFMT_LOAD_ASSUME_SEGMENTS_OK \ + ( \ + EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED | \ + EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP | \ + EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED \ + ) + +/* + Minumum size of the buffer passed to each loader for identification of the + executable +*/ +#define EXEFMT_LOAD_HEADER_SIZE (0x2000) + +/* Special values for the base address of images */ +/* + Base address can't be represented in an ULONG_PTR: any effective load address + will require relocation +*/ +#define EXEFMT_LOAD_BASE_NONE ((ULONG_PTR)-1) + +/* Base address never matters, relocation never required */ +#define EXEFMT_LOAD_BASE_ANY ((ULONG_PTR)-2) + +typedef NTSTATUS (NTAPI * PEXEFMT_CB_READ_FILE) +( + IN PVOID File, + IN PLARGE_INTEGER Offset, + IN ULONG Length, + OUT PVOID * Data, + OUT PVOID * AllocBase, + OUT PULONG ReadSize +); + +typedef PMM_SECTION_SEGMENT (NTAPI * PEXEFMT_CB_ALLOCATE_SEGMENTS) +( + IN ULONG NrSegments +); + +typedef NTSTATUS (NTAPI * PEXEFMT_LOADER) +( + IN CONST VOID * FileHeader, + IN SIZE_T FileHeaderSize, + IN PVOID File, + OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject, + OUT PULONG Flags, + IN PEXEFMT_CB_READ_FILE ReadFileCb, + IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb +); + +/* + * STATUS CONSTANTS + */ + +#define FACILITY_ROS_EXEFMT (0x10) + +/* + * Returned by ExeFormat loaders to tell the caller the format isn't supported, + * as opposed to STATUS_INVALID_IMAGE_FORMAT meaning the format is supported, + * but the particular file is malformed + */ +#define STATUS_ROS_EXEFMT_UNKNOWN_FORMAT (0xA0100001) + +/* + * Returned by MmCreateSection to signal successful loading of an executable + * image, saving the caller the effort of determining the executable's format + * again. The full status to return is obtained by performing a bitwise OR of + * STATUS_ROS_EXEFMT_LOADED_FORMAT and the appropriate EXEFMT_LOADED_XXX + */ +#define FACILITY_ROS_EXEFMT_FORMAT (0x11) +#define STATUS_ROS_EXEFMT_LOADED_FORMAT (0x60110000) + +/* non-standard format, ZwQuerySection required to retrieve the format tag */ +#define EXEFMT_LOADED_EXTENDED (0x0000FFFF) + +/* Windows PE32/PE32+ */ +#define EXEFMT_LOADED_PE32 (0x00000000) +#define EXEFMT_LOADED_PE64 (0x00000001) + +/* Wine ELF */ +#define EXEFMT_LOADED_WINE32 (0x00000002) +#define EXEFMT_LOADED_WINE64 (0x00000003) + +/* regular ELF */ +#define EXEFMT_LOADED_ELF32 (0x00000004) +#define EXEFMT_LOADED_ELF64 (0x00000005) + +#endif + +/* EOF */ diff --git a/reactos/lib/ntdll/ldr/elf.c b/reactos/lib/ntdll/ldr/elf.c new file mode 100644 index 00000000000..09a5c11afd4 --- /dev/null +++ b/reactos/lib/ntdll/ldr/elf.c @@ -0,0 +1,2822 @@ +/* $Id: elf.c,v 1.2 2004/12/30 05:59:11 hyperion Exp $ +*/ + +/* + * REACTOS ELF LOADER + * + * ELF run-time linker, ported from FreeBSD by KJK::Hyperion as part of the ELF + * support initiative. Original copyright, licensing and disclaimers follow + */ + +/*- + * Copyright 1996, 1997, 1998, 1999, 2000 John D. Polstra. + * Copyright 2003 Alexander Kabaev . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: src/libexec/rtld-elf/rtld.c,v 1.101 2004/11/02 09:42:21 ssouhlal Exp $ + */ + +/* + * Dynamic linker for ELF. + * + * John Polstra . + */ + +#if 0 + +#ifndef __GNUC__ +#error "GCC is needed to compile this file" +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "debug.h" +#include "rtld.h" +#include "libmap.h" +#include "rtld_tls.h" + +#ifndef COMPAT_32BIT +#define PATH_RTLD "/libexec/ld-elf.so.1" +#else +#define PATH_RTLD "/libexec/ld-elf32.so.1" +#endif + +/* Types. */ +typedef void (*func_ptr_type)(); +typedef void * (*path_enum_proc) (const char *path, size_t len, void *arg); + +/* + * This structure provides a reentrant way to keep a list of objects and + * check which ones have already been processed in some way. + */ +typedef struct Struct_DoneList { + const Obj_Entry **objs; /* Array of object pointers */ + unsigned int num_alloc; /* Allocated size of the array */ + unsigned int num_used; /* Number of array slots used */ +} DoneList; + +/* + * Function declarations. + */ +static const char *basename(const char *); +static void die(void); +static void digest_dynamic(Obj_Entry *, int); +static Obj_Entry *digest_phdr(const Elf_Phdr *, int, caddr_t, const char *); +static Obj_Entry *dlcheck(void *); +static int do_search_info(const Obj_Entry *obj, int, struct dl_serinfo *); +static bool donelist_check(DoneList *, const Obj_Entry *); +static void errmsg_restore(char *); +static char *errmsg_save(void); +static void *fill_search_info(const char *, size_t, void *); +static char *find_library(const char *, const Obj_Entry *); +static const char *gethints(void); +static void init_dag(Obj_Entry *); +static void init_dag1(Obj_Entry *root, Obj_Entry *obj, DoneList *); +static void init_rtld(caddr_t); +static void initlist_add_neededs(Needed_Entry *needed, Objlist *list); +static void initlist_add_objects(Obj_Entry *obj, Obj_Entry **tail, + Objlist *list); +static bool is_exported(const Elf_Sym *); +static void linkmap_add(Obj_Entry *); +static void linkmap_delete(Obj_Entry *); +static int load_needed_objects(Obj_Entry *); +static int load_preload_objects(void); +static Obj_Entry *load_object(char *); +static Obj_Entry *obj_from_addr(const void *); +static void objlist_call_fini(Objlist *); +static void objlist_call_init(Objlist *); +static void objlist_clear(Objlist *); +static Objlist_Entry *objlist_find(Objlist *, const Obj_Entry *); +static void objlist_init(Objlist *); +static void objlist_push_head(Objlist *, Obj_Entry *); +static void objlist_push_tail(Objlist *, Obj_Entry *); +static void objlist_remove(Objlist *, Obj_Entry *); +static void objlist_remove_unref(Objlist *); +static void *path_enumerate(const char *, path_enum_proc, void *); +static int relocate_objects(Obj_Entry *, bool, Obj_Entry *); +static int rtld_dirname(const char *, char *); +static void rtld_exit(void); +static char *search_library_path(const char *, const char *); +static const void **get_program_var_addr(const char *name); +static void set_program_var(const char *, const void *); +static const Elf_Sym *symlook_default(const char *, unsigned long hash, + const Obj_Entry *refobj, const Obj_Entry **defobj_out, bool in_plt); +static const Elf_Sym *symlook_list(const char *, unsigned long, + Objlist *, const Obj_Entry **, bool in_plt, DoneList *); +static void trace_loaded_objects(Obj_Entry *obj); +static void unlink_object(Obj_Entry *); +static void unload_object(Obj_Entry *); +static void unref_dag(Obj_Entry *); +static void ref_dag(Obj_Entry *); + +void r_debug_state(struct r_debug*, struct link_map*); + +/* + * Data declarations. + */ +static char *error_message; /* Message for dlerror(), or NULL */ +struct r_debug r_debug; /* for GDB; */ +static bool libmap_disable; /* Disable libmap */ +static bool trust; /* False for setuid and setgid programs */ +static char *ld_bind_now; /* Environment variable for immediate binding */ +static char *ld_debug; /* Environment variable for debugging */ +static char *ld_library_path; /* Environment variable for search path */ +static char *ld_preload; /* Environment variable for libraries to + load first */ +static char *ld_tracing; /* Called from ldd to print libs */ +static Obj_Entry *obj_list; /* Head of linked list of shared objects */ +static Obj_Entry **obj_tail; /* Link field of last object in list */ +static Obj_Entry *obj_main; /* The main program shared object */ +static Obj_Entry obj_rtld; /* The dynamic linker shared object */ +static unsigned int obj_count; /* Number of objects in obj_list */ + +static Objlist list_global = /* Objects dlopened with RTLD_GLOBAL */ + STAILQ_HEAD_INITIALIZER(list_global); +static Objlist list_main = /* Objects loaded at program startup */ + STAILQ_HEAD_INITIALIZER(list_main); +static Objlist list_fini = /* Objects needing fini() calls */ + STAILQ_HEAD_INITIALIZER(list_fini); + +static Elf_Sym sym_zero; /* For resolving undefined weak refs. */ + +#define GDB_STATE(s,m) r_debug.r_state = s; r_debug_state(&r_debug,m); + +extern Elf_Dyn _DYNAMIC; +#pragma weak _DYNAMIC +#ifndef RTLD_IS_DYNAMIC +#define RTLD_IS_DYNAMIC() (&_DYNAMIC != NULL) +#endif + +/* + * These are the functions the dynamic linker exports to application + * programs. They are the only symbols the dynamic linker is willing + * to export from itself. + */ +static func_ptr_type exports[] = { + (func_ptr_type) &_rtld_error, + (func_ptr_type) &dlclose, + (func_ptr_type) &dlerror, + (func_ptr_type) &dlopen, + (func_ptr_type) &dlsym, + (func_ptr_type) &dladdr, + (func_ptr_type) &dllockinit, + (func_ptr_type) &dlinfo, + (func_ptr_type) &_rtld_thread_init, +#ifdef __i386__ + (func_ptr_type) &___tls_get_addr, +#endif + (func_ptr_type) &__tls_get_addr, + (func_ptr_type) &_rtld_allocate_tls, + (func_ptr_type) &_rtld_free_tls, + NULL +}; + +/* + * Global declarations normally provided by crt1. The dynamic linker is + * not built with crt1, so we have to provide them ourselves. + */ +char *__progname; +char **environ; + +/* + * Globals to control TLS allocation. + */ +size_t tls_last_offset; /* Static TLS offset of last module */ +size_t tls_last_size; /* Static TLS size of last module */ +size_t tls_static_space; /* Static TLS space allocated */ +int tls_dtv_generation = 1; /* Used to detect when dtv size changes */ +int tls_max_index = 1; /* Largest module index allocated */ + +/* + * Fill in a DoneList with an allocation large enough to hold all of + * the currently-loaded objects. Keep this as a macro since it calls + * alloca and we want that to occur within the scope of the caller. + */ +#define donelist_init(dlp) \ + ((dlp)->objs = alloca(obj_count * sizeof (dlp)->objs[0]), \ + assert((dlp)->objs != NULL), \ + (dlp)->num_alloc = obj_count, \ + (dlp)->num_used = 0) + +/* + * Main entry point for dynamic linking. The first argument is the + * stack pointer. The stack is expected to be laid out as described + * in the SVR4 ABI specification, Intel 386 Processor Supplement. + * Specifically, the stack pointer points to a word containing + * ARGC. Following that in the stack is a null-terminated sequence + * of pointers to argument strings. Then comes a null-terminated + * sequence of pointers to environment strings. Finally, there is a + * sequence of "auxiliary vector" entries. + * + * The second argument points to a place to store the dynamic linker's + * exit procedure pointer and the third to a place to store the main + * program's object. + * + * The return value is the main program's entry point. + */ +func_ptr_type +_rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) +{ + Elf_Auxinfo *aux_info[AT_COUNT]; + int i; + int argc; + char **argv; + char **env; + Elf_Auxinfo *aux; + Elf_Auxinfo *auxp; + const char *argv0; + Objlist_Entry *entry; + Obj_Entry *obj; + Obj_Entry **preload_tail; + Objlist initlist; + int lockstate; + + /* + * On entry, the dynamic linker itself has not been relocated yet. + * Be very careful not to reference any global data until after + * init_rtld has returned. It is OK to reference file-scope statics + * and string constants, and to call static and global functions. + */ + + /* Find the auxiliary vector on the stack. */ + argc = *sp++; + argv = (char **) sp; + sp += argc + 1; /* Skip over arguments and NULL terminator */ + env = (char **) sp; + while (*sp++ != 0) /* Skip over environment, and NULL terminator */ + ; + aux = (Elf_Auxinfo *) sp; + + /* Digest the auxiliary vector. */ + for (i = 0; i < AT_COUNT; i++) + aux_info[i] = NULL; + for (auxp = aux; auxp->a_type != AT_NULL; auxp++) { + if (auxp->a_type < AT_COUNT) + aux_info[auxp->a_type] = auxp; + } + + /* Initialize and relocate ourselves. */ + assert(aux_info[AT_BASE] != NULL); + init_rtld((caddr_t) aux_info[AT_BASE]->a_un.a_ptr); + + __progname = obj_rtld.path; + argv0 = argv[0] != NULL ? argv[0] : "(null)"; + environ = env; + + trust = !issetugid(); + + ld_bind_now = getenv(LD_ "BIND_NOW"); + if (trust) { + ld_debug = getenv(LD_ "DEBUG"); + libmap_disable = getenv(LD_ "LIBMAP_DISABLE") != NULL; + ld_library_path = getenv(LD_ "LIBRARY_PATH"); + ld_preload = getenv(LD_ "PRELOAD"); + } + ld_tracing = getenv(LD_ "TRACE_LOADED_OBJECTS"); + + if (ld_debug != NULL && *ld_debug != '\0') + debug = 1; + dbg("%s is initialized, base address = %p", __progname, + (caddr_t) aux_info[AT_BASE]->a_un.a_ptr); + dbg("RTLD dynamic = %p", obj_rtld.dynamic); + dbg("RTLD pltgot = %p", obj_rtld.pltgot); + + /* + * Load the main program, or process its program header if it is + * already loaded. + */ + if (aux_info[AT_EXECFD] != NULL) { /* Load the main program. */ + int fd = aux_info[AT_EXECFD]->a_un.a_val; + dbg("loading main program"); + obj_main = map_object(fd, argv0, NULL); + close(fd); + if (obj_main == NULL) + die(); + } else { /* Main program already loaded. */ + const Elf_Phdr *phdr; + int phnum; + caddr_t entry; + + dbg("processing main program's program header"); + assert(aux_info[AT_PHDR] != NULL); + phdr = (const Elf_Phdr *) aux_info[AT_PHDR]->a_un.a_ptr; + assert(aux_info[AT_PHNUM] != NULL); + phnum = aux_info[AT_PHNUM]->a_un.a_val; + assert(aux_info[AT_PHENT] != NULL); + assert(aux_info[AT_PHENT]->a_un.a_val == sizeof(Elf_Phdr)); + assert(aux_info[AT_ENTRY] != NULL); + entry = (caddr_t) aux_info[AT_ENTRY]->a_un.a_ptr; + if ((obj_main = digest_phdr(phdr, phnum, entry, argv0)) == NULL) + die(); + } + + obj_main->path = xstrdup(argv0); + obj_main->mainprog = true; + + /* + * Get the actual dynamic linker pathname from the executable if + * possible. (It should always be possible.) That ensures that + * gdb will find the right dynamic linker even if a non-standard + * one is being used. + */ + if (obj_main->interp != NULL && + strcmp(obj_main->interp, obj_rtld.path) != 0) { + free(obj_rtld.path); + obj_rtld.path = xstrdup(obj_main->interp); + __progname = obj_rtld.path; + } + + digest_dynamic(obj_main, 0); + + linkmap_add(obj_main); + linkmap_add(&obj_rtld); + + /* Link the main program into the list of objects. */ + *obj_tail = obj_main; + obj_tail = &obj_main->next; + obj_count++; + /* Make sure we don't call the main program's init and fini functions. */ + obj_main->init = obj_main->fini = (Elf_Addr)NULL; + + /* Initialize a fake symbol for resolving undefined weak references. */ + sym_zero.st_info = ELF_ST_INFO(STB_GLOBAL, STT_NOTYPE); + sym_zero.st_shndx = SHN_UNDEF; + + if (!libmap_disable) + libmap_disable = (bool)lm_init(); + + dbg("loading LD_PRELOAD libraries"); + if (load_preload_objects() == -1) + die(); + preload_tail = obj_tail; + + dbg("loading needed objects"); + if (load_needed_objects(obj_main) == -1) + die(); + + /* Make a list of all objects loaded at startup. */ + for (obj = obj_list; obj != NULL; obj = obj->next) { + objlist_push_tail(&list_main, obj); + obj->refcount++; + } + + if (ld_tracing) { /* We're done */ + trace_loaded_objects(obj_main); + exit(0); + } + + if (getenv(LD_ "DUMP_REL_PRE") != NULL) { + dump_relocations(obj_main); + exit (0); + } + + /* setup TLS for main thread */ + dbg("initializing initial thread local storage"); + STAILQ_FOREACH(entry, &list_main, link) { + /* + * Allocate all the initial objects out of the static TLS + * block even if they didn't ask for it. + */ + allocate_tls_offset(entry->obj); + } + allocate_initial_tls(obj_list); + + if (relocate_objects(obj_main, + ld_bind_now != NULL && *ld_bind_now != '\0', &obj_rtld) == -1) + die(); + + dbg("doing copy relocations"); + if (do_copy_relocations(obj_main) == -1) + die(); + + if (getenv(LD_ "DUMP_REL_POST") != NULL) { + dump_relocations(obj_main); + exit (0); + } + + dbg("initializing key program variables"); + set_program_var("__progname", argv[0] != NULL ? basename(argv[0]) : ""); + set_program_var("environ", env); + + dbg("initializing thread locks"); + lockdflt_init(); + + /* Make a list of init functions to call. */ + objlist_init(&initlist); + initlist_add_objects(obj_list, preload_tail, &initlist); + + r_debug_state(NULL, &obj_main->linkmap); /* say hello to gdb! */ + + objlist_call_init(&initlist); + lockstate = wlock_acquire(rtld_bind_lock); + objlist_clear(&initlist); + wlock_release(rtld_bind_lock, lockstate); + + dbg("transferring control to program entry point = %p", obj_main->entry); + + /* Return the exit procedure and the program entry point. */ + *exit_proc = rtld_exit; + *objp = obj_main; + return (func_ptr_type) obj_main->entry; +} + +#endif /* 0 */ + +Elf_Addr +_rtld_bind(Obj_Entry *obj, Elf_Word reloff) +{ + const Elf_Rel *rel; + const Elf_Sym *def; + const Obj_Entry *defobj; + Elf_Addr *where; + Elf_Addr target; + int lockstate; + + lockstate = rlock_acquire(rtld_bind_lock); + if (obj->pltrel) + rel = (const Elf_Rel *) ((caddr_t) obj->pltrel + reloff); + else + rel = (const Elf_Rel *) ((caddr_t) obj->pltrela + reloff); + + where = (Elf_Addr *) (obj->relocbase + rel->r_offset); + def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, true, NULL); + if (def == NULL) + die(); + + target = (Elf_Addr)(defobj->relocbase + def->st_value); + + dbg("\"%s\" in \"%s\" ==> %p in \"%s\"", + defobj->strtab + def->st_name, basename(obj->path), + (void *)target, basename(defobj->path)); + + /* + * Write the new contents for the jmpslot. Note that depending on + * architecture, the value which we need to return back to the + * lazy binding trampoline may or may not be the target + * address. The value returned from reloc_jmpslot() is the value + * that the trampoline needs. + */ + target = reloc_jmpslot(where, target, defobj, obj, rel); + rlock_release(rtld_bind_lock, lockstate); + return target; +} + +#if 0 + +/* + * Error reporting function. Use it like printf. If formats the message + * into a buffer, and sets things up so that the next call to dlerror() + * will return the message. + */ +void +_rtld_error(const char *fmt, ...) +{ + static char buf[512]; + va_list ap; + + va_start(ap, fmt); + vsnprintf(buf, sizeof buf, fmt, ap); + error_message = buf; + va_end(ap); +} + +/* + * Return a dynamically-allocated copy of the current error message, if any. + */ +static char * +errmsg_save(void) +{ + return error_message == NULL ? NULL : xstrdup(error_message); +} + +/* + * Restore the current error message from a copy which was previously saved + * by errmsg_save(). The copy is freed. + */ +static void +errmsg_restore(char *saved_msg) +{ + if (saved_msg == NULL) + error_message = NULL; + else { + _rtld_error("%s", saved_msg); + free(saved_msg); + } +} + +static const char * +basename(const char *name) +{ + const char *p = strrchr(name, '/'); + return p != NULL ? p + 1 : name; +} + +static void +die(void) +{ + const char *msg = dlerror(); + + if (msg == NULL) + msg = "Fatal error"; + errx(1, "%s", msg); +} + +#endif /* 0 */ + +/* + * Process a shared object's DYNAMIC section, and save the important + * information in its Obj_Entry structure. + */ +static void +digest_dynamic(Obj_Entry *obj, int early) +{ + const Elf_Dyn *dynp; + Needed_Entry **needed_tail = &obj->needed; + const Elf_Dyn *dyn_rpath = NULL; + int plttype = DT_REL; + + obj->bind_now = false; + for (dynp = obj->dynamic; dynp->d_tag != DT_NULL; dynp++) { + switch (dynp->d_tag) { + + case DT_REL: + obj->rel = (const Elf_Rel *) (obj->relocbase + dynp->d_un.d_ptr); + break; + + case DT_RELSZ: + obj->relsize = dynp->d_un.d_val; + break; + + case DT_RELENT: + assert(dynp->d_un.d_val == sizeof(Elf_Rel)); + break; + + case DT_JMPREL: + obj->pltrel = (const Elf_Rel *) + (obj->relocbase + dynp->d_un.d_ptr); + break; + + case DT_PLTRELSZ: + obj->pltrelsize = dynp->d_un.d_val; + break; + + case DT_RELA: + obj->rela = (const Elf_Rela *) (obj->relocbase + dynp->d_un.d_ptr); + break; + + case DT_RELASZ: + obj->relasize = dynp->d_un.d_val; + break; + + case DT_RELAENT: + assert(dynp->d_un.d_val == sizeof(Elf_Rela)); + break; + + case DT_PLTREL: + plttype = dynp->d_un.d_val; + assert(dynp->d_un.d_val == DT_REL || plttype == DT_RELA); + break; + + case DT_SYMTAB: + obj->symtab = (const Elf_Sym *) + (obj->relocbase + dynp->d_un.d_ptr); + break; + + case DT_SYMENT: + assert(dynp->d_un.d_val == sizeof(Elf_Sym)); + break; + + case DT_STRTAB: + obj->strtab = (const char *) (obj->relocbase + dynp->d_un.d_ptr); + break; + + case DT_STRSZ: + obj->strsize = dynp->d_un.d_val; + break; + + case DT_HASH: + { + const Elf_Hashelt *hashtab = (const Elf_Hashelt *) + (obj->relocbase + dynp->d_un.d_ptr); + obj->nbuckets = hashtab[0]; + obj->nchains = hashtab[1]; + obj->buckets = hashtab + 2; + obj->chains = obj->buckets + obj->nbuckets; + } + break; + + case DT_NEEDED: + if (!obj->rtld) { + Needed_Entry *nep = NEW(Needed_Entry); + nep->name = dynp->d_un.d_val; + nep->obj = NULL; + nep->next = NULL; + + *needed_tail = nep; + needed_tail = &nep->next; + } + break; + + case DT_PLTGOT: + obj->pltgot = (Elf_Addr *) (obj->relocbase + dynp->d_un.d_ptr); + break; + + case DT_TEXTREL: + obj->textrel = true; + break; + + case DT_SYMBOLIC: + obj->symbolic = true; + break; + + case DT_RPATH: + case DT_RUNPATH: /* XXX: process separately */ + /* + * We have to wait until later to process this, because we + * might not have gotten the address of the string table yet. + */ + dyn_rpath = dynp; + break; + + case DT_SONAME: + /* Not used by the dynamic linker. */ + break; + + case DT_INIT: + obj->init = (Elf_Addr) (obj->relocbase + dynp->d_un.d_ptr); + break; + + case DT_FINI: + obj->fini = (Elf_Addr) (obj->relocbase + dynp->d_un.d_ptr); + break; + + case DT_DEBUG: + /* XXX - not implemented yet */ + if (!early) + dbg("Filling in DT_DEBUG entry"); + ((Elf_Dyn*)dynp)->d_un.d_ptr = (Elf_Addr) &r_debug; + break; + + case DT_FLAGS: + if (dynp->d_un.d_val & DF_ORIGIN) { + obj->origin_path = xmalloc(PATH_MAX); + if (rtld_dirname(obj->path, obj->origin_path) == -1) + die(); + } + if (dynp->d_un.d_val & DF_SYMBOLIC) + obj->symbolic = true; + if (dynp->d_un.d_val & DF_TEXTREL) + obj->textrel = true; + if (dynp->d_un.d_val & DF_BIND_NOW) + obj->bind_now = true; + if (dynp->d_un.d_val & DF_STATIC_TLS) + ; + break; + + default: + if (!early) { + dbg("Ignoring d_tag %ld = %#lx", (long)dynp->d_tag, + (long)dynp->d_tag); + } + break; + } + } + + obj->traced = false; + + if (plttype == DT_RELA) { + obj->pltrela = (const Elf_Rela *) obj->pltrel; + obj->pltrel = NULL; + obj->pltrelasize = obj->pltrelsize; + obj->pltrelsize = 0; + } + + if (dyn_rpath != NULL) + obj->rpath = obj->strtab + dyn_rpath->d_un.d_val; +} + +/* + * Process a shared object's program header. This is used only for the + * main program, when the kernel has already loaded the main program + * into memory before calling the dynamic linker. It creates and + * returns an Obj_Entry structure. + */ +static Obj_Entry * +digest_phdr(const Elf_Phdr *phdr, int phnum, caddr_t entry, const char *path) +{ + Obj_Entry *obj; + const Elf_Phdr *phlimit = phdr + phnum; + const Elf_Phdr *ph; + int nsegs = 0; + + obj = obj_new(); + for (ph = phdr; ph < phlimit; ph++) { + switch (ph->p_type) { + + case PT_PHDR: + if ((const Elf_Phdr *)ph->p_vaddr != phdr) { + _rtld_error("%s: invalid PT_PHDR", path); + return NULL; + } + obj->phdr = (const Elf_Phdr *) ph->p_vaddr; + obj->phsize = ph->p_memsz; + break; + + case PT_INTERP: + obj->interp = (const char *) ph->p_vaddr; + break; + + case PT_LOAD: + if (nsegs == 0) { /* First load segment */ + obj->vaddrbase = trunc_page(ph->p_vaddr); + obj->mapbase = (caddr_t) obj->vaddrbase; + obj->relocbase = obj->mapbase - obj->vaddrbase; + obj->textsize = round_page(ph->p_vaddr + ph->p_memsz) - + obj->vaddrbase; + } else { /* Last load segment */ + obj->mapsize = round_page(ph->p_vaddr + ph->p_memsz) - + obj->vaddrbase; + } + nsegs++; + break; + + case PT_DYNAMIC: + obj->dynamic = (const Elf_Dyn *) ph->p_vaddr; + break; + + case PT_TLS: + obj->tlsindex = 1; + obj->tlssize = ph->p_memsz; + obj->tlsalign = ph->p_align; + obj->tlsinitsize = ph->p_filesz; + obj->tlsinit = (void*) ph->p_vaddr; + break; + } + } + if (nsegs < 1) { + _rtld_error("%s: too few PT_LOAD segments", path); + return NULL; + } + + obj->entry = entry; + return obj; +} + +#if 0 + +static Obj_Entry * +dlcheck(void *handle) +{ + Obj_Entry *obj; + + for (obj = obj_list; obj != NULL; obj = obj->next) + if (obj == (Obj_Entry *) handle) + break; + + if (obj == NULL || obj->refcount == 0 || obj->dl_refcount == 0) { + _rtld_error("Invalid shared object handle %p", handle); + return NULL; + } + return obj; +} + +/* + * If the given object is already in the donelist, return true. Otherwise + * add the object to the list and return false. + */ +static bool +donelist_check(DoneList *dlp, const Obj_Entry *obj) +{ + unsigned int i; + + for (i = 0; i < dlp->num_used; i++) + if (dlp->objs[i] == obj) + return true; + /* + * Our donelist allocation should always be sufficient. But if + * our threads locking isn't working properly, more shared objects + * could have been loaded since we allocated the list. That should + * never happen, but we'll handle it properly just in case it does. + */ + if (dlp->num_used < dlp->num_alloc) + dlp->objs[dlp->num_used++] = obj; + return false; +} + +#endif /* 0 */ + +/* + * Hash function for symbol table lookup. Don't even think about changing + * this. It is specified by the System V ABI. + */ +unsigned long +elf_hash(const char *name) +{ + const unsigned char *p = (const unsigned char *) name; + unsigned long h = 0; + unsigned long g; + + while (*p != '\0') { + h = (h << 4) + *p++; + if ((g = h & 0xf0000000) != 0) + h ^= g >> 24; + h &= ~g; + } + return h; +} + +#if 0 + +/* + * Find the library with the given name, and return its full pathname. + * The returned string is dynamically allocated. Generates an error + * message and returns NULL if the library cannot be found. + * + * If the second argument is non-NULL, then it refers to an already- + * loaded shared object, whose library search path will be searched. + * + * The search order is: + * LD_LIBRARY_PATH + * rpath in the referencing file + * ldconfig hints + * /lib:/usr/lib + */ +static char * +find_library(const char *xname, const Obj_Entry *refobj) +{ + char *pathname; + char *name; + + if (strchr(xname, '/') != NULL) { /* Hard coded pathname */ + if (xname[0] != '/' && !trust) { + _rtld_error("Absolute pathname required for shared object \"%s\"", + xname); + return NULL; + } + return xstrdup(xname); + } + + if (libmap_disable || (refobj == NULL) || + (name = lm_find(refobj->path, xname)) == NULL) + name = (char *)xname; + + dbg(" Searching for \"%s\"", name); + + if ((pathname = search_library_path(name, ld_library_path)) != NULL || + (refobj != NULL && + (pathname = search_library_path(name, refobj->rpath)) != NULL) || + (pathname = search_library_path(name, gethints())) != NULL || + (pathname = search_library_path(name, STANDARD_LIBRARY_PATH)) != NULL) + return pathname; + + if(refobj != NULL && refobj->path != NULL) { + _rtld_error("Shared object \"%s\" not found, required by \"%s\"", + name, basename(refobj->path)); + } else { + _rtld_error("Shared object \"%s\" not found", name); + } + return NULL; +} + +#endif /* 0 */ + +/* + * Given a symbol number in a referencing object, find the corresponding + * definition of the symbol. Returns a pointer to the symbol, or NULL if + * no definition was found. Returns a pointer to the Obj_Entry of the + * defining object via the reference parameter DEFOBJ_OUT. + */ +const Elf_Sym * +find_symdef(unsigned long symnum, const Obj_Entry *refobj, + const Obj_Entry **defobj_out, bool in_plt, SymCache *cache) +{ + const Elf_Sym *ref; + const Elf_Sym *def; + const Obj_Entry *defobj; + const char *name; + unsigned long hash; + + /* + * If we have already found this symbol, get the information from + * the cache. + */ + if (symnum >= refobj->nchains) + return NULL; /* Bad object */ + if (cache != NULL && cache[symnum].sym != NULL) { + *defobj_out = cache[symnum].obj; + return cache[symnum].sym; + } + + ref = refobj->symtab + symnum; + name = refobj->strtab + ref->st_name; + defobj = NULL; + + /* + * We don't have to do a full scale lookup if the symbol is local. + * We know it will bind to the instance in this load module; to + * which we already have a pointer (ie ref). By not doing a lookup, + * we not only improve performance, but it also avoids unresolvable + * symbols when local symbols are not in the hash table. This has + * been seen with the ia64 toolchain. + */ + if (ELF_ST_BIND(ref->st_info) != STB_LOCAL) { + if (ELF_ST_TYPE(ref->st_info) == STT_SECTION) { + _rtld_error("%s: Bogus symbol table entry %lu", refobj->path, + symnum); + } + hash = elf_hash(name); + def = symlook_default(name, hash, refobj, &defobj, in_plt); + } else { + def = ref; + defobj = refobj; + } + + /* + * If we found no definition and the reference is weak, treat the + * symbol as having the value zero. + */ + if (def == NULL && ELF_ST_BIND(ref->st_info) == STB_WEAK) { + def = &sym_zero; + defobj = obj_main; + } + + if (def != NULL) { + *defobj_out = defobj; + /* Record the information in the cache to avoid subsequent lookups. */ + if (cache != NULL) { + cache[symnum].sym = def; + cache[symnum].obj = defobj; + } + } else { + if (refobj != &obj_rtld) + _rtld_error("%s: Undefined symbol \"%s\"", refobj->path, name); + } + return def; +} + +#if 0 + +/* + * Return the search path from the ldconfig hints file, reading it if + * necessary. Returns NULL if there are problems with the hints file, + * or if the search path there is empty. + */ +static const char * +gethints(void) +{ + static char *hints; + + if (hints == NULL) { + int fd; + struct elfhints_hdr hdr; + char *p; + + /* Keep from trying again in case the hints file is bad. */ + hints = ""; + + if ((fd = open(_PATH_ELF_HINTS, O_RDONLY)) == -1) + return NULL; + if (read(fd, &hdr, sizeof hdr) != sizeof hdr || + hdr.magic != ELFHINTS_MAGIC || + hdr.version != 1) { + close(fd); + return NULL; + } + p = xmalloc(hdr.dirlistlen + 1); + if (lseek(fd, hdr.strtab + hdr.dirlist, SEEK_SET) == -1 || + read(fd, p, hdr.dirlistlen + 1) != (ssize_t)hdr.dirlistlen + 1) { + free(p); + close(fd); + return NULL; + } + hints = p; + close(fd); + } + return hints[0] != '\0' ? hints : NULL; +} + +static void +init_dag(Obj_Entry *root) +{ + DoneList donelist; + + donelist_init(&donelist); + init_dag1(root, root, &donelist); +} + +static void +init_dag1(Obj_Entry *root, Obj_Entry *obj, DoneList *dlp) +{ + const Needed_Entry *needed; + + if (donelist_check(dlp, obj)) + return; + + obj->refcount++; + objlist_push_tail(&obj->dldags, root); + objlist_push_tail(&root->dagmembers, obj); + for (needed = obj->needed; needed != NULL; needed = needed->next) + if (needed->obj != NULL) + init_dag1(root, needed->obj, dlp); +} + +/* + * Initialize the dynamic linker. The argument is the address at which + * the dynamic linker has been mapped into memory. The primary task of + * this function is to relocate the dynamic linker. + */ +static void +init_rtld(caddr_t mapbase) +{ + Obj_Entry objtmp; /* Temporary rtld object */ + + /* + * Conjure up an Obj_Entry structure for the dynamic linker. + * + * The "path" member can't be initialized yet because string constatns + * cannot yet be acessed. Below we will set it correctly. + */ + memset(&objtmp, 0, sizeof(objtmp)); + objtmp.path = NULL; + objtmp.rtld = true; + objtmp.mapbase = mapbase; +#ifdef PIC + objtmp.relocbase = mapbase; +#endif + if (RTLD_IS_DYNAMIC()) { + objtmp.dynamic = rtld_dynamic(&objtmp); + digest_dynamic(&objtmp, 1); + assert(objtmp.needed == NULL); + assert(!objtmp.textrel); + + /* + * Temporarily put the dynamic linker entry into the object list, so + * that symbols can be found. + */ + + relocate_objects(&objtmp, true, &objtmp); + } + + /* Initialize the object list. */ + obj_tail = &obj_list; + + /* Now that non-local variables can be accesses, copy out obj_rtld. */ + memcpy(&obj_rtld, &objtmp, sizeof(obj_rtld)); + + /* Replace the path with a dynamically allocated copy. */ + obj_rtld.path = xstrdup(PATH_RTLD); + + r_debug.r_brk = r_debug_state; + r_debug.r_state = RT_CONSISTENT; +} + +/* + * Add the init functions from a needed object list (and its recursive + * needed objects) to "list". This is not used directly; it is a helper + * function for initlist_add_objects(). The write lock must be held + * when this function is called. + */ +static void +initlist_add_neededs(Needed_Entry *needed, Objlist *list) +{ + /* Recursively process the successor needed objects. */ + if (needed->next != NULL) + initlist_add_neededs(needed->next, list); + + /* Process the current needed object. */ + if (needed->obj != NULL) + initlist_add_objects(needed->obj, &needed->obj->next, list); +} + +/* + * Scan all of the DAGs rooted in the range of objects from "obj" to + * "tail" and add their init functions to "list". This recurses over + * the DAGs and ensure the proper init ordering such that each object's + * needed libraries are initialized before the object itself. At the + * same time, this function adds the objects to the global finalization + * list "list_fini" in the opposite order. The write lock must be + * held when this function is called. + */ +static void +initlist_add_objects(Obj_Entry *obj, Obj_Entry **tail, Objlist *list) +{ + if (obj->init_done) + return; + obj->init_done = true; + + /* Recursively process the successor objects. */ + if (&obj->next != tail) + initlist_add_objects(obj->next, tail, list); + + /* Recursively process the needed objects. */ + if (obj->needed != NULL) + initlist_add_neededs(obj->needed, list); + + /* Add the object to the init list. */ + if (obj->init != (Elf_Addr)NULL) + objlist_push_tail(list, obj); + + /* Add the object to the global fini list in the reverse order. */ + if (obj->fini != (Elf_Addr)NULL) + objlist_push_head(&list_fini, obj); +} + +#ifndef FPTR_TARGET +#define FPTR_TARGET(f) ((Elf_Addr) (f)) +#endif + +static bool +is_exported(const Elf_Sym *def) +{ + Elf_Addr value; + const func_ptr_type *p; + + value = (Elf_Addr)(obj_rtld.relocbase + def->st_value); + for (p = exports; *p != NULL; p++) + if (FPTR_TARGET(*p) == value) + return true; + return false; +} + +/* + * Given a shared object, traverse its list of needed objects, and load + * each of them. Returns 0 on success. Generates an error message and + * returns -1 on failure. + */ +static int +load_needed_objects(Obj_Entry *first) +{ + Obj_Entry *obj; + + for (obj = first; obj != NULL; obj = obj->next) { + Needed_Entry *needed; + + for (needed = obj->needed; needed != NULL; needed = needed->next) { + const char *name = obj->strtab + needed->name; + char *path = find_library(name, obj); + + needed->obj = NULL; + if (path == NULL && !ld_tracing) + return -1; + + if (path) { + needed->obj = load_object(path); + if (needed->obj == NULL && !ld_tracing) + return -1; /* XXX - cleanup */ + } + } + } + + return 0; +} + +static int +load_preload_objects(void) +{ + char *p = ld_preload; + static const char delim[] = " \t:;"; + + if (p == NULL) + return 0; + + p += strspn(p, delim); + while (*p != '\0') { + size_t len = strcspn(p, delim); + char *path; + char savech; + + savech = p[len]; + p[len] = '\0'; + if ((path = find_library(p, NULL)) == NULL) + return -1; + if (load_object(path) == NULL) + return -1; /* XXX - cleanup */ + p[len] = savech; + p += len; + p += strspn(p, delim); + } + return 0; +} + +/* + * Load a shared object into memory, if it is not already loaded. The + * argument must be a string allocated on the heap. This function assumes + * responsibility for freeing it when necessary. + * + * Returns a pointer to the Obj_Entry for the object. Returns NULL + * on failure. + */ +static Obj_Entry * +load_object(char *path) +{ + Obj_Entry *obj; + int fd = -1; + struct stat sb; + + for (obj = obj_list->next; obj != NULL; obj = obj->next) + if (strcmp(obj->path, path) == 0) + break; + + /* + * If we didn't find a match by pathname, open the file and check + * again by device and inode. This avoids false mismatches caused + * by multiple links or ".." in pathnames. + * + * To avoid a race, we open the file and use fstat() rather than + * using stat(). + */ + if (obj == NULL) { + if ((fd = open(path, O_RDONLY)) == -1) { + _rtld_error("Cannot open \"%s\"", path); + return NULL; + } + if (fstat(fd, &sb) == -1) { + _rtld_error("Cannot fstat \"%s\"", path); + close(fd); + return NULL; + } + for (obj = obj_list->next; obj != NULL; obj = obj->next) { + if (obj->ino == sb.st_ino && obj->dev == sb.st_dev) { + close(fd); + break; + } + } + } + + if (obj == NULL) { /* First use of this object, so we must map it in */ + dbg("loading \"%s\"", path); + obj = map_object(fd, path, &sb); + close(fd); + if (obj == NULL) { + free(path); + return NULL; + } + + obj->path = path; + digest_dynamic(obj, 0); + + *obj_tail = obj; + obj_tail = &obj->next; + obj_count++; + linkmap_add(obj); /* for GDB & dlinfo() */ + + dbg(" %p .. %p: %s", obj->mapbase, + obj->mapbase + obj->mapsize - 1, obj->path); + if (obj->textrel) + dbg(" WARNING: %s has impure text", obj->path); + } else + free(path); + + return obj; +} + +static Obj_Entry * +obj_from_addr(const void *addr) +{ + Obj_Entry *obj; + + for (obj = obj_list; obj != NULL; obj = obj->next) { + if (addr < (void *) obj->mapbase) + continue; + if (addr < (void *) (obj->mapbase + obj->mapsize)) + return obj; + } + return NULL; +} + +/* + * Call the finalization functions for each of the objects in "list" + * which are unreferenced. All of the objects are expected to have + * non-NULL fini functions. + */ +static void +objlist_call_fini(Objlist *list) +{ + Objlist_Entry *elm; + char *saved_msg; + + /* + * Preserve the current error message since a fini function might + * call into the dynamic linker and overwrite it. + */ + saved_msg = errmsg_save(); + STAILQ_FOREACH(elm, list, link) { + if (elm->obj->refcount == 0) { + dbg("calling fini function for %s at %p", elm->obj->path, + (void *)elm->obj->fini); + call_initfini_pointer(elm->obj, elm->obj->fini); + } + } + errmsg_restore(saved_msg); +} + +/* + * Call the initialization functions for each of the objects in + * "list". All of the objects are expected to have non-NULL init + * functions. + */ +static void +objlist_call_init(Objlist *list) +{ + Objlist_Entry *elm; + char *saved_msg; + + /* + * Preserve the current error message since an init function might + * call into the dynamic linker and overwrite it. + */ + saved_msg = errmsg_save(); + STAILQ_FOREACH(elm, list, link) { + dbg("calling init function for %s at %p", elm->obj->path, + (void *)elm->obj->init); + call_initfini_pointer(elm->obj, elm->obj->init); + } + errmsg_restore(saved_msg); +} + +static void +objlist_clear(Objlist *list) +{ + Objlist_Entry *elm; + + while (!STAILQ_EMPTY(list)) { + elm = STAILQ_FIRST(list); + STAILQ_REMOVE_HEAD(list, link); + free(elm); + } +} + +static Objlist_Entry * +objlist_find(Objlist *list, const Obj_Entry *obj) +{ + Objlist_Entry *elm; + + STAILQ_FOREACH(elm, list, link) + if (elm->obj == obj) + return elm; + return NULL; +} + +static void +objlist_init(Objlist *list) +{ + STAILQ_INIT(list); +} + +static void +objlist_push_head(Objlist *list, Obj_Entry *obj) +{ + Objlist_Entry *elm; + + elm = NEW(Objlist_Entry); + elm->obj = obj; + STAILQ_INSERT_HEAD(list, elm, link); +} + +static void +objlist_push_tail(Objlist *list, Obj_Entry *obj) +{ + Objlist_Entry *elm; + + elm = NEW(Objlist_Entry); + elm->obj = obj; + STAILQ_INSERT_TAIL(list, elm, link); +} + +static void +objlist_remove(Objlist *list, Obj_Entry *obj) +{ + Objlist_Entry *elm; + + if ((elm = objlist_find(list, obj)) != NULL) { + STAILQ_REMOVE(list, elm, Struct_Objlist_Entry, link); + free(elm); + } +} + +/* + * Remove all of the unreferenced objects from "list". + */ +static void +objlist_remove_unref(Objlist *list) +{ + Objlist newlist; + Objlist_Entry *elm; + + STAILQ_INIT(&newlist); + while (!STAILQ_EMPTY(list)) { + elm = STAILQ_FIRST(list); + STAILQ_REMOVE_HEAD(list, link); + if (elm->obj->refcount == 0) + free(elm); + else + STAILQ_INSERT_TAIL(&newlist, elm, link); + } + *list = newlist; +} + +#endif /* 0 */ + +/* + * Relocate newly-loaded shared objects. The argument is a pointer to + * the Obj_Entry for the first such object. All objects from the first + * to the end of the list of objects are relocated. Returns 0 on success, + * or -1 on failure. + */ +static int +relocate_objects(Obj_Entry *first, bool bind_now, Obj_Entry *rtldobj) +{ + Obj_Entry *obj; + + for (obj = first; obj != NULL; obj = obj->next) { + if (obj != rtldobj) + dbg("relocating \"%s\"", obj->path); + if (obj->nbuckets == 0 || obj->nchains == 0 || obj->buckets == NULL || + obj->symtab == NULL || obj->strtab == NULL) { + _rtld_error("%s: Shared object has no run-time symbol table", + obj->path); + return -1; + } + + if (obj->textrel) { + /* There are relocations to the write-protected text segment. */ + if (mprotect(obj->mapbase, obj->textsize, + PROT_READ|PROT_WRITE|PROT_EXEC) == -1) { + _rtld_error("%s: Cannot write-enable text segment: %s", + obj->path, strerror(errno)); + return -1; + } + } + + /* Process the non-PLT relocations. */ + if (reloc_non_plt(obj, rtldobj)) + return -1; + + if (obj->textrel) { /* Re-protected the text segment. */ + if (mprotect(obj->mapbase, obj->textsize, + PROT_READ|PROT_EXEC) == -1) { + _rtld_error("%s: Cannot write-protect text segment: %s", + obj->path, strerror(errno)); + return -1; + } + } + + /* Process the PLT relocations. */ + if (reloc_plt(obj) == -1) + return -1; + /* Relocate the jump slots if we are doing immediate binding. */ + if (obj->bind_now || bind_now) + if (reloc_jmpslots(obj) == -1) + return -1; + + + /* + * Set up the magic number and version in the Obj_Entry. These + * were checked in the crt1.o from the original ElfKit, so we + * set them for backward compatibility. + */ + obj->magic = RTLD_MAGIC; + obj->version = RTLD_VERSION; + + /* Set the special PLT or GOT entries. */ + init_pltgot(obj); + } + + return 0; +} + +#if 0 + +/* + * Cleanup procedure. It will be called (by the atexit mechanism) just + * before the process exits. + */ +static void +rtld_exit(void) +{ + Obj_Entry *obj; + + dbg("rtld_exit()"); + /* Clear all the reference counts so the fini functions will be called. */ + for (obj = obj_list; obj != NULL; obj = obj->next) + obj->refcount = 0; + objlist_call_fini(&list_fini); + /* No need to remove the items from the list, since we are exiting. */ + if (!libmap_disable) + lm_fini(); +} + +static void * +path_enumerate(const char *path, path_enum_proc callback, void *arg) +{ +#ifdef COMPAT_32BIT + const char *trans; +#endif + if (path == NULL) + return (NULL); + + path += strspn(path, ":;"); + while (*path != '\0') { + size_t len; + char *res; + + len = strcspn(path, ":;"); +#ifdef COMPAT_32BIT + trans = lm_findn(NULL, path, len); + if (trans) + res = callback(trans, strlen(trans), arg); + else +#endif + res = callback(path, len, arg); + + if (res != NULL) + return (res); + + path += len; + path += strspn(path, ":;"); + } + + return (NULL); +} + +struct try_library_args { + const char *name; + size_t namelen; + char *buffer; + size_t buflen; +}; + +static void * +try_library_path(const char *dir, size_t dirlen, void *param) +{ + struct try_library_args *arg; + + arg = param; + if (*dir == '/' || trust) { + char *pathname; + + if (dirlen + 1 + arg->namelen + 1 > arg->buflen) + return (NULL); + + pathname = arg->buffer; + strncpy(pathname, dir, dirlen); + pathname[dirlen] = '/'; + strcpy(pathname + dirlen + 1, arg->name); + + dbg(" Trying \"%s\"", pathname); + if (access(pathname, F_OK) == 0) { /* We found it */ + pathname = xmalloc(dirlen + 1 + arg->namelen + 1); + strcpy(pathname, arg->buffer); + return (pathname); + } + } + return (NULL); +} + +static char * +search_library_path(const char *name, const char *path) +{ + char *p; + struct try_library_args arg; + + if (path == NULL) + return NULL; + + arg.name = name; + arg.namelen = strlen(name); + arg.buffer = xmalloc(PATH_MAX); + arg.buflen = PATH_MAX; + + p = path_enumerate(path, try_library_path, &arg); + + free(arg.buffer); + + return (p); +} + +int +dlclose(void *handle) +{ + Obj_Entry *root; + int lockstate; + + lockstate = wlock_acquire(rtld_bind_lock); + root = dlcheck(handle); + if (root == NULL) { + wlock_release(rtld_bind_lock, lockstate); + return -1; + } + + /* Unreference the object and its dependencies. */ + root->dl_refcount--; + + unref_dag(root); + + if (root->refcount == 0) { + /* + * The object is no longer referenced, so we must unload it. + * First, call the fini functions with no locks held. + */ + wlock_release(rtld_bind_lock, lockstate); + objlist_call_fini(&list_fini); + lockstate = wlock_acquire(rtld_bind_lock); + objlist_remove_unref(&list_fini); + + /* Finish cleaning up the newly-unreferenced objects. */ + GDB_STATE(RT_DELETE,&root->linkmap); + unload_object(root); + GDB_STATE(RT_CONSISTENT,NULL); + } + wlock_release(rtld_bind_lock, lockstate); + return 0; +} + +const char * +dlerror(void) +{ + char *msg = error_message; + error_message = NULL; + return msg; +} + +/* + * This function is deprecated and has no effect. + */ +void +dllockinit(void *context, + void *(*lock_create)(void *context), + void (*rlock_acquire)(void *lock), + void (*wlock_acquire)(void *lock), + void (*lock_release)(void *lock), + void (*lock_destroy)(void *lock), + void (*context_destroy)(void *context)) +{ + static void *cur_context; + static void (*cur_context_destroy)(void *); + + /* Just destroy the context from the previous call, if necessary. */ + if (cur_context_destroy != NULL) + cur_context_destroy(cur_context); + cur_context = context; + cur_context_destroy = context_destroy; +} + +void * +dlopen(const char *name, int mode) +{ + Obj_Entry **old_obj_tail; + Obj_Entry *obj; + Objlist initlist; + int result, lockstate; + + ld_tracing = (mode & RTLD_TRACE) == 0 ? NULL : "1"; + if (ld_tracing != NULL) + environ = (char **)*get_program_var_addr("environ"); + + objlist_init(&initlist); + + lockstate = wlock_acquire(rtld_bind_lock); + GDB_STATE(RT_ADD,NULL); + + old_obj_tail = obj_tail; + obj = NULL; + if (name == NULL) { + obj = obj_main; + obj->refcount++; + } else { + char *path = find_library(name, obj_main); + if (path != NULL) + obj = load_object(path); + } + + if (obj) { + obj->dl_refcount++; + if (mode & RTLD_GLOBAL && objlist_find(&list_global, obj) == NULL) + objlist_push_tail(&list_global, obj); + mode &= RTLD_MODEMASK; + if (*old_obj_tail != NULL) { /* We loaded something new. */ + assert(*old_obj_tail == obj); + + result = load_needed_objects(obj); + if (result != -1 && ld_tracing) + goto trace; + + if (result == -1 || + (init_dag(obj), relocate_objects(obj, mode == RTLD_NOW, + &obj_rtld)) == -1) { + obj->dl_refcount--; + unref_dag(obj); + if (obj->refcount == 0) + unload_object(obj); + obj = NULL; + } else { + /* Make list of init functions to call. */ + initlist_add_objects(obj, &obj->next, &initlist); + } + } else { + + /* Bump the reference counts for objects on this DAG. */ + ref_dag(obj); + + if (ld_tracing) + goto trace; + } + } + + GDB_STATE(RT_CONSISTENT,obj ? &obj->linkmap : NULL); + + /* Call the init functions with no locks held. */ + wlock_release(rtld_bind_lock, lockstate); + objlist_call_init(&initlist); + lockstate = wlock_acquire(rtld_bind_lock); + objlist_clear(&initlist); + wlock_release(rtld_bind_lock, lockstate); + return obj; +trace: + trace_loaded_objects(obj); + wlock_release(rtld_bind_lock, lockstate); + exit(0); +} + +void * +dlsym(void *handle, const char *name) +{ + const Obj_Entry *obj; + unsigned long hash; + const Elf_Sym *def; + const Obj_Entry *defobj; + int lockstate; + + hash = elf_hash(name); + def = NULL; + defobj = NULL; + + lockstate = rlock_acquire(rtld_bind_lock); + if (handle == NULL || handle == RTLD_NEXT || + handle == RTLD_DEFAULT || handle == RTLD_SELF) { + void *retaddr; + + retaddr = __builtin_return_address(0); /* __GNUC__ only */ + if ((obj = obj_from_addr(retaddr)) == NULL) { + _rtld_error("Cannot determine caller's shared object"); + rlock_release(rtld_bind_lock, lockstate); + return NULL; + } + if (handle == NULL) { /* Just the caller's shared object. */ + def = symlook_obj(name, hash, obj, true); + defobj = obj; + } else if (handle == RTLD_NEXT || /* Objects after caller's */ + handle == RTLD_SELF) { /* ... caller included */ + if (handle == RTLD_NEXT) + obj = obj->next; + for (; obj != NULL; obj = obj->next) { + if ((def = symlook_obj(name, hash, obj, true)) != NULL) { + defobj = obj; + break; + } + } + } else { + assert(handle == RTLD_DEFAULT); + def = symlook_default(name, hash, obj, &defobj, true); + } + } else { + if ((obj = dlcheck(handle)) == NULL) { + rlock_release(rtld_bind_lock, lockstate); + return NULL; + } + + if (obj->mainprog) { + DoneList donelist; + + /* Search main program and all libraries loaded by it. */ + donelist_init(&donelist); + def = symlook_list(name, hash, &list_main, &defobj, true, + &donelist); + } else { + /* + * XXX - This isn't correct. The search should include the whole + * DAG rooted at the given object. + */ + def = symlook_obj(name, hash, obj, true); + defobj = obj; + } + } + + if (def != NULL) { + rlock_release(rtld_bind_lock, lockstate); + + /* + * The value required by the caller is derived from the value + * of the symbol. For the ia64 architecture, we need to + * construct a function descriptor which the caller can use to + * call the function with the right 'gp' value. For other + * architectures and for non-functions, the value is simply + * the relocated value of the symbol. + */ + if (ELF_ST_TYPE(def->st_info) == STT_FUNC) + return make_function_pointer(def, defobj); + else + return defobj->relocbase + def->st_value; + } + + _rtld_error("Undefined symbol \"%s\"", name); + rlock_release(rtld_bind_lock, lockstate); + return NULL; +} + +int +dladdr(const void *addr, Dl_info *info) +{ + const Obj_Entry *obj; + const Elf_Sym *def; + void *symbol_addr; + unsigned long symoffset; + int lockstate; + + lockstate = rlock_acquire(rtld_bind_lock); + obj = obj_from_addr(addr); + if (obj == NULL) { + _rtld_error("No shared object contains address"); + rlock_release(rtld_bind_lock, lockstate); + return 0; + } + info->dli_fname = obj->path; + info->dli_fbase = obj->mapbase; + info->dli_saddr = (void *)0; + info->dli_sname = NULL; + + /* + * Walk the symbol list looking for the symbol whose address is + * closest to the address sent in. + */ + for (symoffset = 0; symoffset < obj->nchains; symoffset++) { + def = obj->symtab + symoffset; + + /* + * For skip the symbol if st_shndx is either SHN_UNDEF or + * SHN_COMMON. + */ + if (def->st_shndx == SHN_UNDEF || def->st_shndx == SHN_COMMON) + continue; + + /* + * If the symbol is greater than the specified address, or if it + * is further away from addr than the current nearest symbol, + * then reject it. + */ + symbol_addr = obj->relocbase + def->st_value; + if (symbol_addr > addr || symbol_addr < info->dli_saddr) + continue; + + /* Update our idea of the nearest symbol. */ + info->dli_sname = obj->strtab + def->st_name; + info->dli_saddr = symbol_addr; + + /* Exact match? */ + if (info->dli_saddr == addr) + break; + } + rlock_release(rtld_bind_lock, lockstate); + return 1; +} + +int +dlinfo(void *handle, int request, void *p) +{ + const Obj_Entry *obj; + int error, lockstate; + + lockstate = rlock_acquire(rtld_bind_lock); + + if (handle == NULL || handle == RTLD_SELF) { + void *retaddr; + + retaddr = __builtin_return_address(0); /* __GNUC__ only */ + if ((obj = obj_from_addr(retaddr)) == NULL) + _rtld_error("Cannot determine caller's shared object"); + } else + obj = dlcheck(handle); + + if (obj == NULL) { + rlock_release(rtld_bind_lock, lockstate); + return (-1); + } + + error = 0; + switch (request) { + case RTLD_DI_LINKMAP: + *((struct link_map const **)p) = &obj->linkmap; + break; + case RTLD_DI_ORIGIN: + error = rtld_dirname(obj->path, p); + break; + + case RTLD_DI_SERINFOSIZE: + case RTLD_DI_SERINFO: + error = do_search_info(obj, request, (struct dl_serinfo *)p); + break; + + default: + _rtld_error("Invalid request %d passed to dlinfo()", request); + error = -1; + } + + rlock_release(rtld_bind_lock, lockstate); + + return (error); +} + +struct fill_search_info_args { + int request; + unsigned int flags; + Dl_serinfo *serinfo; + Dl_serpath *serpath; + char *strspace; +}; + +static void * +fill_search_info(const char *dir, size_t dirlen, void *param) +{ + struct fill_search_info_args *arg; + + arg = param; + + if (arg->request == RTLD_DI_SERINFOSIZE) { + arg->serinfo->dls_cnt ++; + arg->serinfo->dls_size += dirlen + 1; + } else { + struct dl_serpath *s_entry; + + s_entry = arg->serpath; + s_entry->dls_name = arg->strspace; + s_entry->dls_flags = arg->flags; + + strncpy(arg->strspace, dir, dirlen); + arg->strspace[dirlen] = '\0'; + + arg->strspace += dirlen + 1; + arg->serpath++; + } + + return (NULL); +} + +static int +do_search_info(const Obj_Entry *obj, int request, struct dl_serinfo *info) +{ + struct dl_serinfo _info; + struct fill_search_info_args args; + + args.request = RTLD_DI_SERINFOSIZE; + args.serinfo = &_info; + + _info.dls_size = __offsetof(struct dl_serinfo, dls_serpath); + _info.dls_cnt = 0; + + path_enumerate(ld_library_path, fill_search_info, &args); + path_enumerate(obj->rpath, fill_search_info, &args); + path_enumerate(gethints(), fill_search_info, &args); + path_enumerate(STANDARD_LIBRARY_PATH, fill_search_info, &args); + + + if (request == RTLD_DI_SERINFOSIZE) { + info->dls_size = _info.dls_size; + info->dls_cnt = _info.dls_cnt; + return (0); + } + + if (info->dls_cnt != _info.dls_cnt || info->dls_size != _info.dls_size) { + _rtld_error("Uninitialized Dl_serinfo struct passed to dlinfo()"); + return (-1); + } + + args.request = RTLD_DI_SERINFO; + args.serinfo = info; + args.serpath = &info->dls_serpath[0]; + args.strspace = (char *)&info->dls_serpath[_info.dls_cnt]; + + args.flags = LA_SER_LIBPATH; + if (path_enumerate(ld_library_path, fill_search_info, &args) != NULL) + return (-1); + + args.flags = LA_SER_RUNPATH; + if (path_enumerate(obj->rpath, fill_search_info, &args) != NULL) + return (-1); + + args.flags = LA_SER_CONFIG; + if (path_enumerate(gethints(), fill_search_info, &args) != NULL) + return (-1); + + args.flags = LA_SER_DEFAULT; + if (path_enumerate(STANDARD_LIBRARY_PATH, fill_search_info, &args) != NULL) + return (-1); + return (0); +} + +static int +rtld_dirname(const char *path, char *bname) +{ + const char *endp; + + /* Empty or NULL string gets treated as "." */ + if (path == NULL || *path == '\0') { + bname[0] = '.'; + bname[1] = '\0'; + return (0); + } + + /* Strip trailing slashes */ + endp = path + strlen(path) - 1; + while (endp > path && *endp == '/') + endp--; + + /* Find the start of the dir */ + while (endp > path && *endp != '/') + endp--; + + /* Either the dir is "/" or there are no slashes */ + if (endp == path) { + bname[0] = *endp == '/' ? '/' : '.'; + bname[1] = '\0'; + return (0); + } else { + do { + endp--; + } while (endp > path && *endp == '/'); + } + + if (endp - path + 2 > PATH_MAX) + { + _rtld_error("Filename is too long: %s", path); + return(-1); + } + + strncpy(bname, path, endp - path + 1); + bname[endp - path + 1] = '\0'; + return (0); +} + +static void +linkmap_add(Obj_Entry *obj) +{ + struct link_map *l = &obj->linkmap; + struct link_map *prev; + + obj->linkmap.l_name = obj->path; + obj->linkmap.l_addr = obj->mapbase; + obj->linkmap.l_ld = obj->dynamic; +#ifdef __mips__ + /* GDB needs load offset on MIPS to use the symbols */ + obj->linkmap.l_offs = obj->relocbase; +#endif + + if (r_debug.r_map == NULL) { + r_debug.r_map = l; + return; + } + + /* + * Scan to the end of the list, but not past the entry for the + * dynamic linker, which we want to keep at the very end. + */ + for (prev = r_debug.r_map; + prev->l_next != NULL && prev->l_next != &obj_rtld.linkmap; + prev = prev->l_next) + ; + + /* Link in the new entry. */ + l->l_prev = prev; + l->l_next = prev->l_next; + if (l->l_next != NULL) + l->l_next->l_prev = l; + prev->l_next = l; +} + +static void +linkmap_delete(Obj_Entry *obj) +{ + struct link_map *l = &obj->linkmap; + + if (l->l_prev == NULL) { + if ((r_debug.r_map = l->l_next) != NULL) + l->l_next->l_prev = NULL; + return; + } + + if ((l->l_prev->l_next = l->l_next) != NULL) + l->l_next->l_prev = l->l_prev; +} + +/* + * Function for the debugger to set a breakpoint on to gain control. + * + * The two parameters allow the debugger to easily find and determine + * what the runtime loader is doing and to whom it is doing it. + * + * When the loadhook trap is hit (r_debug_state, set at program + * initialization), the arguments can be found on the stack: + * + * +8 struct link_map *m + * +4 struct r_debug *rd + * +0 RetAddr + */ +void +r_debug_state(struct r_debug* rd, struct link_map *m) +{ +} + +/* + * Get address of the pointer variable in the main program. + */ +static const void ** +get_program_var_addr(const char *name) +{ + const Obj_Entry *obj; + unsigned long hash; + + hash = elf_hash(name); + for (obj = obj_main; obj != NULL; obj = obj->next) { + const Elf_Sym *def; + + if ((def = symlook_obj(name, hash, obj, false)) != NULL) { + const void **addr; + + addr = (const void **)(obj->relocbase + def->st_value); + return addr; + } + } + return NULL; +} + +/* + * Set a pointer variable in the main program to the given value. This + * is used to set key variables such as "environ" before any of the + * init functions are called. + */ +static void +set_program_var(const char *name, const void *value) +{ + const void **addr; + + if ((addr = get_program_var_addr(name)) != NULL) { + dbg("\"%s\": *%p <-- %p", name, addr, value); + *addr = value; + } +} + +/* + * Given a symbol name in a referencing object, find the corresponding + * definition of the symbol. Returns a pointer to the symbol, or NULL if + * no definition was found. Returns a pointer to the Obj_Entry of the + * defining object via the reference parameter DEFOBJ_OUT. + */ +static const Elf_Sym * +symlook_default(const char *name, unsigned long hash, + const Obj_Entry *refobj, const Obj_Entry **defobj_out, bool in_plt) +{ + DoneList donelist; + const Elf_Sym *def; + const Elf_Sym *symp; + const Obj_Entry *obj; + const Obj_Entry *defobj; + const Objlist_Entry *elm; + def = NULL; + defobj = NULL; + donelist_init(&donelist); + + /* Look first in the referencing object if linked symbolically. */ + if (refobj->symbolic && !donelist_check(&donelist, refobj)) { + symp = symlook_obj(name, hash, refobj, in_plt); + if (symp != NULL) { + def = symp; + defobj = refobj; + } + } + + /* Search all objects loaded at program start up. */ + if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) { + symp = symlook_list(name, hash, &list_main, &obj, in_plt, &donelist); + if (symp != NULL && + (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) { + def = symp; + defobj = obj; + } + } + + /* Search all DAGs whose roots are RTLD_GLOBAL objects. */ + STAILQ_FOREACH(elm, &list_global, link) { + if (def != NULL && ELF_ST_BIND(def->st_info) != STB_WEAK) + break; + symp = symlook_list(name, hash, &elm->obj->dagmembers, &obj, in_plt, + &donelist); + if (symp != NULL && + (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) { + def = symp; + defobj = obj; + } + } + + /* Search all dlopened DAGs containing the referencing object. */ + STAILQ_FOREACH(elm, &refobj->dldags, link) { + if (def != NULL && ELF_ST_BIND(def->st_info) != STB_WEAK) + break; + symp = symlook_list(name, hash, &elm->obj->dagmembers, &obj, in_plt, + &donelist); + if (symp != NULL && + (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) { + def = symp; + defobj = obj; + } + } + + /* + * Search the dynamic linker itself, and possibly resolve the + * symbol from there. This is how the application links to + * dynamic linker services such as dlopen. Only the values listed + * in the "exports" array can be resolved from the dynamic linker. + */ + if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) { + symp = symlook_obj(name, hash, &obj_rtld, in_plt); + if (symp != NULL && is_exported(symp)) { + def = symp; + defobj = &obj_rtld; + } + } + + if (def != NULL) + *defobj_out = defobj; + return def; +} + +static const Elf_Sym * +symlook_list(const char *name, unsigned long hash, Objlist *objlist, + const Obj_Entry **defobj_out, bool in_plt, DoneList *dlp) +{ + const Elf_Sym *symp; + const Elf_Sym *def; + const Obj_Entry *defobj; + const Objlist_Entry *elm; + + def = NULL; + defobj = NULL; + STAILQ_FOREACH(elm, objlist, link) { + if (donelist_check(dlp, elm->obj)) + continue; + if ((symp = symlook_obj(name, hash, elm->obj, in_plt)) != NULL) { + if (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK) { + def = symp; + defobj = elm->obj; + if (ELF_ST_BIND(def->st_info) != STB_WEAK) + break; + } + } + } + if (def != NULL) + *defobj_out = defobj; + return def; +} + +#endif /* 0 */ + +/* + * Search the symbol table of a single shared object for a symbol of + * the given name. Returns a pointer to the symbol, or NULL if no + * definition was found. + * + * The symbol's hash value is passed in for efficiency reasons; that + * eliminates many recomputations of the hash value. + */ +const Elf_Sym * +symlook_obj(const char *name, unsigned long hash, const Obj_Entry *obj, + bool in_plt) +{ + if (obj->buckets != NULL) { + unsigned long symnum = obj->buckets[hash % obj->nbuckets]; + + while (symnum != STN_UNDEF) { + const Elf_Sym *symp; + const char *strp; + + if (symnum >= obj->nchains) + return NULL; /* Bad object */ + symp = obj->symtab + symnum; + strp = obj->strtab + symp->st_name; + + if (name[0] == strp[0] && strcmp(name, strp) == 0) + return symp->st_shndx != SHN_UNDEF || + (!in_plt && symp->st_value != 0 && + ELF_ST_TYPE(symp->st_info) == STT_FUNC) ? symp : NULL; + + symnum = obj->chains[symnum]; + } + } + return NULL; +} + +#if 0 + +static void +trace_loaded_objects(Obj_Entry *obj) +{ + char *fmt1, *fmt2, *fmt, *main_local, *list_containers; + int c; + + if ((main_local = getenv(LD_ "TRACE_LOADED_OBJECTS_PROGNAME")) == NULL) + main_local = ""; + + if ((fmt1 = getenv(LD_ "TRACE_LOADED_OBJECTS_FMT1")) == NULL) + fmt1 = "\t%o => %p (%x)\n"; + + if ((fmt2 = getenv(LD_ "TRACE_LOADED_OBJECTS_FMT2")) == NULL) + fmt2 = "\t%o (%x)\n"; + + list_containers = getenv(LD_ "TRACE_LOADED_OBJECTS_ALL"); + + for (; obj; obj = obj->next) { + Needed_Entry *needed; + char *name, *path; + bool is_lib; + + if (list_containers && obj->needed != NULL) + printf("%s:\n", obj->path); + for (needed = obj->needed; needed; needed = needed->next) { + if (needed->obj != NULL) { + if (needed->obj->traced && !list_containers) + continue; + needed->obj->traced = true; + path = needed->obj->path; + } else + path = "not found"; + + name = (char *)obj->strtab + needed->name; + is_lib = strncmp(name, "lib", 3) == 0; /* XXX - bogus */ + + fmt = is_lib ? fmt1 : fmt2; + while ((c = *fmt++) != '\0') { + switch (c) { + default: + putchar(c); + continue; + case '\\': + switch (c = *fmt) { + case '\0': + continue; + case 'n': + putchar('\n'); + break; + case 't': + putchar('\t'); + break; + } + break; + case '%': + switch (c = *fmt) { + case '\0': + continue; + case '%': + default: + putchar(c); + break; + case 'A': + printf("%s", main_local); + break; + case 'a': + printf("%s", obj_main->path); + break; + case 'o': + printf("%s", name); + break; +#if 0 + case 'm': + printf("%d", sodp->sod_major); + break; + case 'n': + printf("%d", sodp->sod_minor); + break; +#endif + case 'p': + printf("%s", path); + break; + case 'x': + printf("%p", needed->obj ? needed->obj->mapbase : 0); + break; + } + break; + } + ++fmt; + } + } + } +} + +/* + * Unload a dlopened object and its dependencies from memory and from + * our data structures. It is assumed that the DAG rooted in the + * object has already been unreferenced, and that the object has a + * reference count of 0. + */ +static void +unload_object(Obj_Entry *root) +{ + Obj_Entry *obj; + Obj_Entry **linkp; + + assert(root->refcount == 0); + + /* + * Pass over the DAG removing unreferenced objects from + * appropriate lists. + */ + unlink_object(root); + + /* Unmap all objects that are no longer referenced. */ + linkp = &obj_list->next; + while ((obj = *linkp) != NULL) { + if (obj->refcount == 0) { + dbg("unloading \"%s\"", obj->path); + munmap(obj->mapbase, obj->mapsize); + linkmap_delete(obj); + *linkp = obj->next; + obj_count--; + obj_free(obj); + } else + linkp = &obj->next; + } + obj_tail = linkp; +} + +static void +unlink_object(Obj_Entry *root) +{ + Objlist_Entry *elm; + + if (root->refcount == 0) { + /* Remove the object from the RTLD_GLOBAL list. */ + objlist_remove(&list_global, root); + + /* Remove the object from all objects' DAG lists. */ + STAILQ_FOREACH(elm, &root->dagmembers , link) { + objlist_remove(&elm->obj->dldags, root); + if (elm->obj != root) + unlink_object(elm->obj); + } + } +} + +static void +ref_dag(Obj_Entry *root) +{ + Objlist_Entry *elm; + + STAILQ_FOREACH(elm, &root->dagmembers , link) + elm->obj->refcount++; +} + +static void +unref_dag(Obj_Entry *root) +{ + Objlist_Entry *elm; + + STAILQ_FOREACH(elm, &root->dagmembers , link) + elm->obj->refcount--; +} + +/* + * Common code for MD __tls_get_addr(). + */ +void * +tls_get_addr_common(Elf_Addr** dtvp, int index, size_t offset) +{ + Elf_Addr* dtv = *dtvp; + + /* Check dtv generation in case new modules have arrived */ + if (dtv[0] != tls_dtv_generation) { + Elf_Addr* newdtv; + int to_copy; + + newdtv = calloc(1, (tls_max_index + 2) * sizeof(Elf_Addr)); + to_copy = dtv[1]; + if (to_copy > tls_max_index) + to_copy = tls_max_index; + memcpy(&newdtv[2], &dtv[2], to_copy * sizeof(Elf_Addr)); + newdtv[0] = tls_dtv_generation; + newdtv[1] = tls_max_index; + free(dtv); + *dtvp = newdtv; + } + + /* Dynamically allocate module TLS if necessary */ + if (!dtv[index + 1]) + dtv[index + 1] = (Elf_Addr)allocate_module_tls(index); + + return (void*) (dtv[index + 1] + offset); +} + +/* XXX not sure what variants to use for arm. */ + +#if defined(__ia64__) || defined(__alpha__) || defined(__powerpc__) + +/* + * Allocate Static TLS using the Variant I method. + */ +void * +allocate_tls(Obj_Entry *objs, void *oldtls, size_t tcbsize, size_t tcbalign) +{ + Obj_Entry *obj; + size_t size; + char *tls; + Elf_Addr *dtv, *olddtv; + Elf_Addr addr; + int i; + + size = tls_static_space; + + tls = malloc(size); + dtv = malloc((tls_max_index + 2) * sizeof(Elf_Addr)); + + *(Elf_Addr**) tls = dtv; + + dtv[0] = tls_dtv_generation; + dtv[1] = tls_max_index; + + if (oldtls) { + /* + * Copy the static TLS block over whole. + */ + memcpy(tls + tcbsize, oldtls + tcbsize, tls_static_space - tcbsize); + + /* + * If any dynamic TLS blocks have been created tls_get_addr(), + * move them over. + */ + olddtv = *(Elf_Addr**) oldtls; + for (i = 0; i < olddtv[1]; i++) { + if (olddtv[i+2] < (Elf_Addr)oldtls || + olddtv[i+2] > (Elf_Addr)oldtls + tls_static_space) { + dtv[i+2] = olddtv[i+2]; + olddtv[i+2] = 0; + } + } + + /* + * We assume that all tls blocks are allocated with the same + * size and alignment. + */ + free_tls(oldtls, tcbsize, tcbalign); + } else { + for (obj = objs; obj; obj = obj->next) { + if (obj->tlsoffset) { + addr = (Elf_Addr)tls + obj->tlsoffset; + memset((void*) (addr + obj->tlsinitsize), + 0, obj->tlssize - obj->tlsinitsize); + if (obj->tlsinit) + memcpy((void*) addr, obj->tlsinit, + obj->tlsinitsize); + dtv[obj->tlsindex + 1] = addr; + } else if (obj->tlsindex) { + dtv[obj->tlsindex + 1] = 0; + } + } + } + + return tls; +} + +void +free_tls(void *tls, size_t tcbsize, size_t tcbalign) +{ + size_t size; + Elf_Addr* dtv; + int dtvsize, i; + Elf_Addr tlsstart, tlsend; + + /* + * Figure out the size of the initial TLS block so that we can + * find stuff which __tls_get_addr() allocated dynamically. + */ + size = tls_static_space; + + dtv = ((Elf_Addr**)tls)[0]; + dtvsize = dtv[1]; + tlsstart = (Elf_Addr) tls; + tlsend = tlsstart + size; + for (i = 0; i < dtvsize; i++) { + if (dtv[i+2] < tlsstart || dtv[i+2] > tlsend) { + free((void*) dtv[i+2]); + } + } + + free((void*) tlsstart); +} + +#endif + +#if defined(__i386__) || defined(__amd64__) || defined(__sparc64__) || \ + defined(__arm__) + +/* + * Allocate Static TLS using the Variant II method. + */ +void * +allocate_tls(Obj_Entry *objs, void *oldtls, size_t tcbsize, size_t tcbalign) +{ + Obj_Entry *obj; + size_t size; + char *tls; + Elf_Addr *dtv, *olddtv; + Elf_Addr segbase, oldsegbase, addr; + int i; + + size = round(tls_static_space, tcbalign); + + assert(tcbsize >= 2*sizeof(Elf_Addr)); + tls = malloc(size + tcbsize); + dtv = malloc((tls_max_index + 2) * sizeof(Elf_Addr)); + + segbase = (Elf_Addr)(tls + size); + ((Elf_Addr*)segbase)[0] = segbase; + ((Elf_Addr*)segbase)[1] = (Elf_Addr) dtv; + + dtv[0] = tls_dtv_generation; + dtv[1] = tls_max_index; + + if (oldtls) { + /* + * Copy the static TLS block over whole. + */ + oldsegbase = (Elf_Addr) oldtls; + memcpy((void *)(segbase - tls_static_space), + (const void *)(oldsegbase - tls_static_space), + tls_static_space); + + /* + * If any dynamic TLS blocks have been created tls_get_addr(), + * move them over. + */ + olddtv = ((Elf_Addr**)oldsegbase)[1]; + for (i = 0; i < olddtv[1]; i++) { + if (olddtv[i+2] < oldsegbase - size || olddtv[i+2] > oldsegbase) { + dtv[i+2] = olddtv[i+2]; + olddtv[i+2] = 0; + } + } + + /* + * We assume that this block was the one we created with + * allocate_initial_tls(). + */ + free_tls(oldtls, 2*sizeof(Elf_Addr), sizeof(Elf_Addr)); + } else { + for (obj = objs; obj; obj = obj->next) { + if (obj->tlsoffset) { + addr = segbase - obj->tlsoffset; + memset((void*) (addr + obj->tlsinitsize), + 0, obj->tlssize - obj->tlsinitsize); + if (obj->tlsinit) + memcpy((void*) addr, obj->tlsinit, obj->tlsinitsize); + dtv[obj->tlsindex + 1] = addr; + } else if (obj->tlsindex) { + dtv[obj->tlsindex + 1] = 0; + } + } + } + + return (void*) segbase; +} + +void +free_tls(void *tls, size_t tcbsize, size_t tcbalign) +{ + size_t size; + Elf_Addr* dtv; + int dtvsize, i; + Elf_Addr tlsstart, tlsend; + + /* + * Figure out the size of the initial TLS block so that we can + * find stuff which ___tls_get_addr() allocated dynamically. + */ + size = round(tls_static_space, tcbalign); + + dtv = ((Elf_Addr**)tls)[1]; + dtvsize = dtv[1]; + tlsend = (Elf_Addr) tls; + tlsstart = tlsend - size; + for (i = 0; i < dtvsize; i++) { + if (dtv[i+2] < tlsstart || dtv[i+2] > tlsend) { + free((void*) dtv[i+2]); + } + } + + free((void*) tlsstart); +} + +#endif + +/* + * Allocate TLS block for module with given index. + */ +void * +allocate_module_tls(int index) +{ + Obj_Entry* obj; + char* p; + + for (obj = obj_list; obj; obj = obj->next) { + if (obj->tlsindex == index) + break; + } + if (!obj) { + _rtld_error("Can't find module with TLS index %d", index); + die(); + } + + p = malloc(obj->tlssize); + memcpy(p, obj->tlsinit, obj->tlsinitsize); + memset(p + obj->tlsinitsize, 0, obj->tlssize - obj->tlsinitsize); + + return p; +} + +bool +allocate_tls_offset(Obj_Entry *obj) +{ + size_t off; + + if (obj->tls_done) + return true; + + if (obj->tlssize == 0) { + obj->tls_done = true; + return true; + } + + if (obj->tlsindex == 1) + off = calculate_first_tls_offset(obj->tlssize, obj->tlsalign); + else + off = calculate_tls_offset(tls_last_offset, tls_last_size, + obj->tlssize, obj->tlsalign); + + /* + * If we have already fixed the size of the static TLS block, we + * must stay within that size. When allocating the static TLS, we + * leave a small amount of space spare to be used for dynamically + * loading modules which use static TLS. + */ + if (tls_static_space) { + if (calculate_tls_end(off, obj->tlssize) > tls_static_space) + return false; + } + + tls_last_offset = obj->tlsoffset = off; + tls_last_size = obj->tlssize; + obj->tls_done = true; + + return true; +} + +void * +_rtld_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign) +{ + return allocate_tls(obj_list, oldtls, tcbsize, tcbalign); +} + +void +_rtld_free_tls(void *tcb, size_t tcbsize, size_t tcbalign) +{ + free_tls(tcb, tcbsize, tcbalign); +} + +#endif /* 0 */ diff --git a/reactos/lib/ntdll/ldr/tls.c b/reactos/lib/ntdll/ldr/tls.c deleted file mode 100644 index 285fe9c8205..00000000000 --- a/reactos/lib/ntdll/ldr/tls.c +++ /dev/null @@ -1,127 +0,0 @@ -#define RTL_FOREACH_LIST(PLIST_HEAD__, TYPE__, FIELD__) \ -{ \ - PLIST_ENTRY _RTL_FOREACH_LIST_END = (PLIST_HEAD__); \ - PLIST_ENTRY _RTL_FOREACH_LIST_CUR = _RTL_FOREACH_LIST_END->Flink; \ - TYPE__ * _RTL_ITEM = \ - CONTAINING_RECORD(_RTL_FOREACH_LIST_CUR, TYPE__, FIELD__); \ - \ - for \ - ( \ - ; \ - _RTL_FOREACH_LIST_CUR != _RTL_FOREACH_LIST_END; \ - _RTL_ITEM = CONTAINING_RECORD(_RTL_FOREACH_LIST_CUR, TYPE__, FIELD__) \ - ) - -#define RTL_FOREACH_END } - -NTSTATUS STDCALL LdrpRosTlsAction -( - IN ULONG Reason -) -{ - typedef struct _LDRP_TLS_ENTRY - { - LIST_ENTRY TlsList; - PIMAGE_TLS_DIRECTORY TlsDir; - PLDR_MODULE LdrModule; - } - LDRP_TLS_ENTRY, * PLDRP_TLS_ENTRY; - - static LIST_ENTRY s_leTlsList; - static SIZE_T s_nTlsImagesCount; - - switch(Reason) - { - case DLL_PROCESS_ATTACH: - { - PPEB_LDR_DATA pLdr = NtCurrentPeb()->Ldr; - - InitializeListHead(&s_leTlsList); - s_nTlsImagesCount = 0; - - RTL_FOREACH_LIST - ( - &pLdr->InLoadOrderModuleList, - LDR_MODULE, - InLoadOrderModuleList - ) - { - SIZE_T nSize; - PIMAGE_TLS_DIRECTORY pitdTlsDir = RtlImageDirectoryEntryToData - ( - _RTL_ITEM->BaseAddress, - TRUE, - IMAGE_DIRECTORY_ENTRY_TLS, - &nSize - ); - - if(pitdTlsDir == NULL || nSize < sizeof(IMAGE_TLS_DIRECTORY)) continue; - - PLDRP_TLS_ENTRY plteCur = - RtlAllocateHeap(pPeb->ProcessHeap, 0, sizeof(LDRP_TLS_ENTRY)); - - if(plteCur == NULL) return STATUS_NO_MEMORY; - - InsertTailList(&s_leTlsList, &plteCur->TlsList); - - _RTL_ITEM->TlsIndex = s_nTlsImagesCount; - ++ s_nTlsImagesCount; /* TODO: check for out-of-bounds index */ - - plteCur->LdrModule = _RTL_ITEM; - plteCur->TlsDir = pitdTlsDir; - - *pitdTlsDir->AddressOfIndex = _RTL_ITEM->TlsIndex; - } - RTL_FOREACH_END; - - RtlSetBits(pPeb->TlsBitmap, 0, s_nTlsImagesCount); - - /* fall through */ - } - - case DLL_THREAD_ATTACH: - { - RTL_FOREACH_LIST(&s_leTlsList, LDRP_TLS_ENTRY, TlsList) - { - PBYTE pcTlsData; - PIMAGE_TLS_DIRECTORY pitdTlsDir = _RTL_ITEM->TlsDir; - SIZE_T nInitDataSize = - pitdTlsDir->EndAddressOfRawData - pitdTlsDir->StartAddressOfRawData; - - PIMAGE_TLS_CALLBACK * pitcCallbacks = - (PIMAGE_TLS_CALLBACK *)_RTL_ITEM->TlsDir->AddressOfCallbacks; - - pcTlsData = RtlAllocateHeap - ( - pPeb->ProcessHeap, - 0, - nInitDataSize + pitdTlsDir->SizeOfZeroFill - ); - - if(pcTlsData == NULL) return STATUS_NO_MEMORY; - - pTeb->TlsSlots[_RTL_ITEM->LdrModule->TlsIndex] = pcTlsData; - - RtlMoveMemory(pcTlsData, pitdTlsDir->StartAddressOfRawData, nInitDataSize); - RtlZeroMemory(pcTlsData + nInitDataSize, pitdTlsDir->SizeOfZeroFill); - - if(pitcCallbacks) - for(; *pitcCallbacks; ++ pitcCallbacks) - (*pitcCallbacks)(_RTL_ITEM->LdrModule->BaseAddress, Reason, NULL); - } - RTL_FOREACH_END; - - return STATUS_SUCCESS; - } - - case DLL_THREAD_DETACH: - { - } - - case DLL_PROCESS_DETACH: - { - } - - default: return STATUS_SUCCESS; - } -} diff --git a/reactos/lib/pseh/i386/framebased.asm b/reactos/lib/pseh/i386/framebased.asm index 0db8ad10d0d..0af3e09addb 100644 --- a/reactos/lib/pseh/i386/framebased.asm +++ b/reactos/lib/pseh/i386/framebased.asm @@ -18,8 +18,6 @@ ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ; SOFTWARE. -; DON'T USE THE "cpu" DIRECTIVE BECAUSE NASM 0.98 DOESN'T SUPPORT IT -; cpu 486 segment .text use32 global __SEHCleanHandlerEnvironment diff --git a/reactos/lib/pseh/i386/setjmp.asm b/reactos/lib/pseh/i386/setjmp.asm index a46897071a7..1467459f02a 100644 --- a/reactos/lib/pseh/i386/setjmp.asm +++ b/reactos/lib/pseh/i386/setjmp.asm @@ -18,8 +18,6 @@ ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ; SOFTWARE. -; DON'T USE THE "cpu" DIRECTIVE BECAUSE NASM 0.98 DOESN'T SUPPORT IT -; cpu 486 segment .text use32 ; Note: the undecorated names are for Borland C++ (and possibly other compilers diff --git a/reactos/ntoskrnl/mm/elf.c b/reactos/ntoskrnl/mm/elf.c new file mode 100644 index 00000000000..c355faf9f3b --- /dev/null +++ b/reactos/ntoskrnl/mm/elf.c @@ -0,0 +1,702 @@ +/* $Id: elf.c,v 1.2 2004/12/30 05:59:11 hyperion Exp $ +*/ + +#include + +/*#define NDEBUG*/ +#include + +#include + +#ifndef __ELF_WORD_SIZE +#error __ELF_WORD_SIZE must be defined +#endif + +#include + +/* TODO: Intsafe should be made into a library, as it's generally useful */ +static __inline BOOLEAN Intsafe_CanAddULongPtr +( + IN ULONG_PTR Addend1, + IN ULONG_PTR Addend2 +) +{ + return Addend1 <= (MAXULONG_PTR - Addend2); +} + +#define Intsafe_CanAddSizeT Intsafe_CanAddULongPtr + +static __inline BOOLEAN Intsafe_CanAddULong32 +( + IN ULONG Addend1, + IN ULONG Addend2 +) +{ + return Addend1 <= (MAXULONG - Addend2); +} + +static __inline BOOLEAN Intsafe_AddULong32 +( + OUT PULONG Result, + IN ULONG Addend1, + IN ULONG Addend2 +) +{ + if(!Intsafe_CanAddULong32(Addend1, Addend2)) + return FALSE; + + *Result = Addend1 + Addend2; + return TRUE; +} + +static __inline BOOLEAN Intsafe_CanAddULong64 +( + IN ULONG64 Addend1, + IN ULONG64 Addend2 +) +{ + return Addend1 <= (((ULONG64)-1) - Addend2); +} + +static __inline BOOLEAN Intsafe_AddULong64 +( + OUT PULONG64 Result, + IN ULONG64 Addend1, + IN ULONG64 Addend2 +) +{ + if(!Intsafe_CanAddULong64(Addend1, Addend2)) + return FALSE; + + *Result = Addend1 + Addend2; + return TRUE; +} + +static __inline BOOLEAN Intsafe_CanMulULong32 +( + IN ULONG Factor1, + IN ULONG Factor2 +) +{ + return Factor1 <= (MAXULONG / Factor2); +} + +static __inline BOOLEAN Intsafe_MulULong32 +( + OUT PULONG Result, + IN ULONG Factor1, + IN ULONG Factor2 +) +{ + if(!Intsafe_CanMulULong32(Factor1, Factor2)) + return FALSE; + + *Result = Factor1 * Factor2; + return TRUE; +} + +static __inline BOOLEAN Intsafe_CanOffsetPointer +( + IN CONST VOID * Pointer, + IN SIZE_T Offset +) +{ + /* FIXME: (PVOID)MAXULONG_PTR isn't necessarily a valid address */ + return Intsafe_CanAddULongPtr((ULONG_PTR)Pointer, Offset); +} + +#if __ELF_WORD_SIZE == 32 +#define ElfFmtpAddSize Intsafe_AddULong32 +#define ElfFmtpReadAddr ElfFmtpReadULong +#define ElfFmtpReadOff ElfFmtpReadULong +#define ElfFmtpSafeReadAddr ElfFmtpSafeReadULong +#define ElfFmtpSafeReadOff ElfFmtpSafeReadULong +#define ElfFmtpSafeReadSize ElfFmtpSafeReadULong +#elif __ELF_WORD_SIZE == 64 +#define ElfFmtpAddSize Intsafe_AddULong64 +#define ElfFmtpReadAddr ElfFmtpReadULong64 +#define ElfFmtpReadOff ElfFmtpReadULong64 +#define ElfFmtpSafeReadAddr ElfFmtpSafeReadULong64 +#define ElfFmtpSafeReadOff ElfFmtpSafeReadULong64 +#define ElfFmtpSafeReadSize ElfFmtpSafeReadULong64 +#endif + +/* TODO: these are standard DDK/PSDK macros */ +#define RtlRetrieveUlonglong(DST_, SRC_) \ + (RtlCopyMemory((DST_), (SRC_), sizeof(ULONG64))) + +#ifndef RTL_FIELD_SIZE +#define RTL_FIELD_SIZE(TYPE_, FIELD_) (sizeof(((TYPE_ *)0)->FIELD_)) +#endif + +#ifndef RTL_SIZEOF_THROUGH_FIELD +#define RTL_SIZEOF_THROUGH_FIELD(TYPE_, FIELD_) \ + (FIELD_OFFSET(TYPE_, FIELD_) + RTL_FIELD_SIZE(TYPE_, FIELD_)) +#endif + +#ifndef RTL_CONTAINS_FIELD +#define RTL_CONTAINS_FIELD(P_, SIZE_, FIELD_) \ + ((((char *)(P_)) + (SIZE_)) > (((char *)(&((P_)->FIELD_))) + sizeof((P_)->FIELD_))) +#endif + +#define ELFFMT_FIELDS_EQUAL(TYPE1_, TYPE2_, FIELD_) \ + ( \ + (FIELD_OFFSET(TYPE1_, FIELD_) == FIELD_OFFSET(TYPE2_, FIELD_)) && \ + (RTL_FIELD_SIZE(TYPE1_, FIELD_) == RTL_FIELD_SIZE(TYPE2_, FIELD_)) \ + ) + +#define ELFFMT_MAKE_ULONG64(BYTE1_, BYTE2_, BYTE3_, BYTE4_, BYTE5_, BYTE6_, BYTE7_, BYTE8_) \ + ( \ + (((ULONG64)ELFFMT_MAKE_ULONG(BYTE1_, BYTE2_, BYTE3_, BYTE4_)) << 0) | \ + (((ULONG64)ELFFMT_MAKE_ULONG(BYTE5_, BYTE6_, BYTE7_, BYTE8_)) << 32) \ + ) + +#define ELFFMT_MAKE_ULONG(BYTE1_, BYTE2_, BYTE3_, BYTE4_) \ + ( \ + (((ULONG)ELFFMT_MAKE_USHORT(BYTE1_, BYTE2_)) << 0) | \ + (((ULONG)ELFFMT_MAKE_USHORT(BYTE3_, BYTE4_)) << 16) \ + ) + +#define ELFFMT_MAKE_USHORT(BYTE1_, BYTE2_) \ + ( \ + (((USHORT)(BYTE1_)) << 0) | \ + (((USHORT)(BYTE2_)) << 8) \ + ) + +static __inline ULONG64 ElfFmtpReadULong64 +( + IN ULONG64 Input, + IN ULONG DataType +) +{ + PBYTE p; + + if(DataType == ELF_TARG_DATA) + return Input; + + p = (PBYTE)&Input; + + switch(DataType) + { + case ELFDATA2LSB: return ELFFMT_MAKE_ULONG64(p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); + case ELFDATA2MSB: return ELFFMT_MAKE_ULONG64(p[7], p[6], p[5], p[4], p[3], p[2], p[1], p[0]); + } + + ASSERT(FALSE); + return (ULONG64)-1; +} + +static __inline ULONG ElfFmtpReadULong +( + IN ULONG Input, + IN ULONG DataType +) +{ + PBYTE p; + + if(DataType == ELF_TARG_DATA) + return Input; + + p = (PBYTE)&Input; + + switch(DataType) + { + case ELFDATA2LSB: return ELFFMT_MAKE_ULONG(p[0], p[1], p[2], p[3]); + case ELFDATA2MSB: return ELFFMT_MAKE_ULONG(p[3], p[2], p[1], p[0]); + } + + ASSERT(FALSE); + return (ULONG)-1; +} + +static __inline USHORT ElfFmtpReadUShort +( + IN USHORT Input, + IN ULONG DataType +) +{ + PBYTE p; + + if(DataType == ELF_TARG_DATA) + return Input; + + p = (PBYTE)&Input; + + switch(DataType) + { + case ELFDATA2LSB: return ELFFMT_MAKE_USHORT(p[0], p[1]); + case ELFDATA2MSB: return ELFFMT_MAKE_USHORT(p[1], p[0]); + } + + ASSERT(FALSE); + return (USHORT)-1; +} + +static __inline ULONG64 ElfFmtpSafeReadULong64 +( + IN CONST ULONG64 * Input, + IN ULONG DataType +) +{ + PBYTE p; + ULONG nSafeInput; + + RtlRetrieveUlonglong(&nSafeInput, Input); + + p = (PBYTE)&nSafeInput; + + switch(DataType) + { + case ELFDATA2LSB: return ELFFMT_MAKE_ULONG64(p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); + case ELFDATA2MSB: return ELFFMT_MAKE_ULONG64(p[7], p[6], p[5], p[4], p[3], p[2], p[1], p[0]); + } + + ASSERT(FALSE); + return (ULONG64)-1; +} + +static __inline ULONG ElfFmtpSafeReadULong +( + IN CONST ULONG * Input, + IN ULONG DataType +) +{ + PBYTE p; + ULONG nSafeInput; + + RtlRetrieveUlong(&nSafeInput, Input); + + if(DataType == ELF_TARG_DATA) + return nSafeInput; + + p = (PBYTE)&nSafeInput; + + switch(DataType) + { + case ELFDATA2LSB: return ELFFMT_MAKE_ULONG(p[0], p[1], p[2], p[3]); + case ELFDATA2MSB: return ELFFMT_MAKE_ULONG(p[3], p[2], p[1], p[0]); + } + + ASSERT(FALSE); + return (ULONG)-1; +} + +static __inline BOOLEAN ElfFmtpIsPowerOf2(IN Elf_Addr Number) +{ + if(Number == 0) + return FALSE; + + while((Number % 2) == 0) + Number /= 2; + + return Number == 1; +} + +static __inline Elf_Addr ElfFmtpModPow2 +( + IN Elf_Addr Address, + IN Elf_Addr Alignment +) +{ + ASSERT(sizeof(Elf_Addr) == sizeof(Elf_Size)); + ASSERT(sizeof(Elf_Addr) == sizeof(Elf_Off)); + ASSERT(ElfFmtpIsPowerOf2(Alignment)); + return Address & (Alignment - 1); +} + +static __inline Elf_Addr ElfFmtpAlignDown +( + IN Elf_Addr Address, + IN Elf_Addr Alignment +) +{ + ASSERT(sizeof(Elf_Addr) == sizeof(Elf_Size)); + ASSERT(sizeof(Elf_Addr) == sizeof(Elf_Off)); + ASSERT(ElfFmtpIsPowerOf2(Alignment)); + return Address & ~(Alignment - 1); +} + +static __inline BOOLEAN ElfFmtpAlignUp +( + OUT Elf_Addr * AlignedAddress, + IN Elf_Addr Address, + IN Elf_Addr Alignment +) +{ + Elf_Addr nExcess = ElfFmtpModPow2(Address, Alignment); + + if(nExcess == 0) + { + *AlignedAddress = Address; + return nExcess == 0; + } + else + return ElfFmtpAddSize(AlignedAddress, Address, Alignment - nExcess); +} + +/* + References: + [1] Tool Interface Standards (TIS) Committee, "Executable and Linking Format + (ELF) Specification", Version 1.2 +*/ +NTSTATUS NTAPI +#if __ELF_WORD_SIZE == 32 +Elf32FmtCreateSection +#elif __ELF_WORD_SIZE == 64 +Elf64FmtCreateSection +#endif +( + IN CONST VOID * FileHeader, + IN SIZE_T FileHeaderSize, + IN PVOID File, + OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject, + OUT PULONG Flags, + IN PEXEFMT_CB_READ_FILE ReadFileCb, + IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb +) +{ + NTSTATUS nStatus; + const Elf_Ehdr * pehHeader; + const Elf_Phdr * pphPHdrs; + BOOLEAN fPageAligned; + ULONG nData; + ULONG nPHdrCount; + ULONG cbPHdrSize; + Elf_Off cbPHdrOffset; + PVOID pBuffer; + PMM_SECTION_SEGMENT pssSegments; + Elf_Addr nImageBase; + Elf_Addr nEntryPoint; + ULONG nPrevVirtualEndOfSegment; + ULONG i; + ULONG j; + + (void)Intsafe_AddULong64; + (void)Intsafe_MulULong32; + (void)ElfFmtpReadULong64; + (void)ElfFmtpSafeReadULong64; + (void)ElfFmtpReadULong; + +#define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; } + + pBuffer = NULL; + + nStatus = STATUS_INVALID_IMAGE_FORMAT; + + /* Ensure the file contains the full header */ + /* + EXEFMT_LOAD_HEADER_SIZE is 8KB: enough to contain an ELF header (at least in + all the classes defined as of December 2004). If FileHeaderSize is less than + sizeof(Elf_Ehdr), it means the file itself is small enough not to contain a + full ELF header + */ + ASSERT(sizeof(Elf_Ehdr) <= EXEFMT_LOAD_HEADER_SIZE); + + if(FileHeaderSize < sizeof(Elf_Ehdr)) + DIE(("The file is truncated, doesn't contain the full header\n")); + + pehHeader = FileHeader; + ASSERT(((ULONG_PTR)pehHeader % TYPE_ALIGNMENT(Elf_Ehdr)) == 0); + + nData = pehHeader->e_ident[EI_DATA]; + + /* Validate the header */ + if(ElfFmtpReadUShort(pehHeader->e_ehsize, nData) < sizeof(Elf_Ehdr)) + DIE(("Inconsistent value for e_ehsize\n")); + + /* Calculate size and offset of the program headers */ + cbPHdrSize = ElfFmtpReadUShort(pehHeader->e_phentsize, nData); + + if(cbPHdrSize != sizeof(Elf_Phdr)) + DIE(("Inconsistent value for e_phentsize\n")); + + /* MAXUSHORT * MAXUSHORT < MAXULONG */ + nPHdrCount = ElfFmtpReadUShort(pehHeader->e_phnum, nData); + ASSERT(Intsafe_CanMulULong32(cbPHdrSize, nPHdrCount)); + cbPHdrSize *= nPHdrCount; + + cbPHdrOffset = ElfFmtpReadOff(pehHeader->e_phoff, nData); + + /* The initial header doesn't contain the program headers */ + if(cbPHdrOffset > FileHeaderSize || cbPHdrSize > (FileHeaderSize - cbPHdrOffset)) + { + NTSTATUS nReadStatus; + LARGE_INTEGER lnOffset; + PVOID pData; + ULONG cbReadSize; + + /* Will worry about this when ELF128 comes */ + ASSERT(sizeof(cbPHdrOffset) <= sizeof(lnOffset.QuadPart)); + + lnOffset.QuadPart = (LONG64)cbPHdrOffset; + + /* + We can't support executable files larger than 8 Exabytes - it's a limitation + of the I/O system (only 63-bit offsets are supported). Quote: + + [...] the total amount of printed material in the world is estimated to be + around a fifth of an exabyte. [...] [Source: Wikipedia] + */ + if(lnOffset.u.HighPart < 0) + DIE(("The program header is too far into the file\n")); + + nReadStatus = ReadFileCb + ( + File, + &lnOffset, + cbPHdrSize, + &pData, + &pBuffer, + &cbReadSize + ); + + if(!NT_SUCCESS(nReadStatus)) + { + nStatus = nReadStatus; + DIE(("ReadFile failed, status %08X\n", nStatus)); + } + + ASSERT(pData); + ASSERT(pBuffer); + ASSERT(Intsafe_CanOffsetPointer(pData, cbReadSize)); + + if(cbReadSize < cbPHdrSize) + DIE(("The file didn't contain the program headers\n")); + + /* Force the buffer to be aligned */ + if((ULONG_PTR)pData % TYPE_ALIGNMENT(Elf_Phdr)) + { + ASSERT(((ULONG_PTR)pBuffer % TYPE_ALIGNMENT(Elf_Phdr)) == 0); + RtlMoveMemory(pBuffer, pData, cbPHdrSize); + pphPHdrs = pBuffer; + } + else + pphPHdrs = pData; + } + else + { + ASSERT(Intsafe_CanAddSizeT(cbPHdrOffset, 0)); + ASSERT(Intsafe_CanOffsetPointer(FileHeader, cbPHdrOffset)); + pphPHdrs = (PVOID)((ULONG_PTR)FileHeader + (ULONG_PTR)cbPHdrOffset); + } + + /* Allocate the segments */ + pssSegments = AllocateSegmentsCb(nPHdrCount); + + if(pssSegments == NULL) + { + nStatus = STATUS_INSUFFICIENT_RESOURCES; + DIE(("Out of memory\n")); + } + + ImageSectionObject->Segments = pssSegments; + + fPageAligned = TRUE; + + /* Fill in the segments */ + for(i = 0, j = 0; i < nPHdrCount; ++ i) + { + switch(ElfFmtpSafeReadULong(&pphPHdrs[i].p_type, nData)) + { + case PT_LOAD: + { + static const ULONG ProgramHeaderFlagsToProtect[8] = + { + PAGE_NOACCESS, /* 0 */ + PAGE_EXECUTE_READ, /* PF_X */ + PAGE_READWRITE, /* PF_W */ + PAGE_EXECUTE_READWRITE, /* PF_X | PF_W */ + PAGE_READONLY, /* PF_R */ + PAGE_EXECUTE_READ, /* PF_X | PF_R */ + PAGE_READWRITE, /* PF_W | PF_R */ + PAGE_EXECUTE_READWRITE /* PF_X | PF_W | PF_R */ + }; + + Elf_Size nAlignment; + Elf_Off nFileOffset; + Elf_Addr nVirtualAddr; + Elf_Size nAdj; + Elf_Size nVirtualSize; + Elf_Size nFileSize; + + ASSERT(j <= nPHdrCount); + + /* Retrieve and validate the segment alignment */ + nAlignment = ElfFmtpSafeReadSize(&pphPHdrs[i].p_align, nData); + + if(nAlignment == 0) + nAlignment = 1; + else if(!ElfFmtpIsPowerOf2(nAlignment)) + DIE(("Alignment of loadable segment isn't a power of 2\n")); + + if(nAlignment < PAGE_SIZE) + fPageAligned = FALSE; + + /* Retrieve the addresses and calculate the adjustment */ + nFileOffset = ElfFmtpSafeReadOff(&pphPHdrs[i].p_offset, nData); + nVirtualAddr = ElfFmtpSafeReadAddr(&pphPHdrs[i].p_vaddr, nData); + + nAdj = ElfFmtpModPow2(nFileOffset, nAlignment); + + if(nAdj != ElfFmtpModPow2(nVirtualAddr, nAlignment)) + DIE(("File and memory address of loadable segment not congruent modulo alignment\n")); + + /* Retrieve, adjust and align the file size and memory size */ + if(!ElfFmtpAddSize(&nFileSize, ElfFmtpSafeReadSize(&pphPHdrs[i].p_filesz, nData), nAdj)) + DIE(("Can't adjust the file size of loadable segment\n")); + + if(!ElfFmtpAddSize(&nVirtualSize, ElfFmtpSafeReadSize(&pphPHdrs[i].p_memsz, nData), nAdj)) + DIE(("Can't adjust the memory size of lodable segment\n")); + + if(!ElfFmtpAlignUp(&nVirtualSize, nVirtualSize, nAlignment)) + DIE(("Can't align the memory size of lodable segment\n")); + + if(nFileSize > nVirtualSize) + nFileSize = nVirtualSize; + + if(nVirtualSize > MAXULONG) + DIE(("Virtual image larger than 4GB\n")); + + ASSERT(nFileSize <= MAXULONG); + + pssSegments[j].Length = (ULONG)(nVirtualSize & 0xFFFFFFFF); + pssSegments[j].RawLength = (ULONG)(nFileSize & 0xFFFFFFFF); + + /* File offset */ + nFileOffset = ElfFmtpAlignDown(nFileOffset, nAlignment); + +#if __ELF_WORD_SIZE >= 64 + ASSERT(sizeof(nFileOffset) == sizeof(LONG64)); + + if(((LONG64)nFileOffset) < 0) + DIE(("File offset of loadable segment is too large\n")); +#endif + + pssSegments[j].FileOffset = (LONG64)nFileOffset; + + /* Virtual address */ + nVirtualAddr = ElfFmtpAlignDown(nVirtualAddr, nAlignment); + + if(j == 0) + { + /* First segment: its address is the base address of the image */ + nImageBase = nVirtualAddr; + pssSegments[j].VirtualAddress = 0; + + /* Several places make this assumption */ + if(pssSegments[j].FileOffset != 0) + DIE(("First loadable segment doesn't contain the ELF header\n")); + } + else + { + Elf_Size nVirtualOffset; + + /* Other segment: store the offset from the base address */ + if(nVirtualAddr <= nImageBase) + DIE(("Loadable segments are not sorted\n")); + + nVirtualOffset = nVirtualAddr - nImageBase; + + if(nVirtualOffset > MAXULONG) + DIE(("Virtual image larger than 4GB\n")); + + pssSegments[j].VirtualAddress = (ULONG)(nVirtualOffset & 0xFFFFFFFF); + + if(pssSegments[j].VirtualAddress != nPrevVirtualEndOfSegment) + DIE(("Loadable segments are not sorted and contiguous\n")); + } + + /* Memory protection */ + pssSegments[j].Protection = ProgramHeaderFlagsToProtect + [ + ElfFmtpSafeReadULong(&pphPHdrs[i].p_flags, nData) & (PF_R | PF_W | PF_X) + ]; + + /* Characteristics */ + /* + TODO: need to add support for the shared, non-pageable, non-cacheable and + discardable attributes. This involves extensions to the ELF format, so it's + nothing to be taken lightly + */ + if(pssSegments[j].Protection & PAGE_IS_EXECUTABLE) + { + ImageSectionObject->Executable = TRUE; + pssSegments[j].Characteristics = IMAGE_SCN_CNT_CODE; + } + else if(pssSegments[j].RawLength == 0) + pssSegments[j].Characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA; + else + pssSegments[j].Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA; + + /* Copy-on-write */ + pssSegments[j].WriteCopy = TRUE; + + if(!Intsafe_AddULong32(&nPrevVirtualEndOfSegment, pssSegments[j].VirtualAddress, pssSegments[j].Length)) + DIE(("Virtual image larger than 4GB\n")); + + ++ j; + break; + } + } + } + + if(j == 0) + DIE(("No loadable segments\n")); + + ImageSectionObject->NrSegments = j; + + *Flags = + EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED | + EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP; + + if(fPageAligned) + *Flags |= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED; + + nEntryPoint = ElfFmtpReadAddr(pehHeader->e_entry, nData); + + if(nEntryPoint < nImageBase || nEntryPoint - nImageBase > nPrevVirtualEndOfSegment) + DIE(("Entry point not within the virtual image\n")); + + ASSERT(nEntryPoint >= nImageBase); + ASSERT((nEntryPoint - nImageBase) <= MAXULONG); + ImageSectionObject->EntryPoint = nEntryPoint - nImageBase; + + /* TODO: support Wine executables and read these values from nt_headers */ + ImageSectionObject->ImageCharacteristics |= + IMAGE_FILE_EXECUTABLE_IMAGE | + IMAGE_FILE_LINE_NUMS_STRIPPED | + IMAGE_FILE_LOCAL_SYMS_STRIPPED | + (nImageBase > MAXULONG ? IMAGE_FILE_LARGE_ADDRESS_AWARE : 0) | + IMAGE_FILE_DEBUG_STRIPPED; + + if(nData == ELFDATA2LSB) + ImageSectionObject->ImageCharacteristics |= IMAGE_FILE_BYTES_REVERSED_LO; + else if(nData == ELFDATA2MSB) + ImageSectionObject->ImageCharacteristics |= IMAGE_FILE_BYTES_REVERSED_HI; + + /* Base address outside the possible address space */ + if(nImageBase > MAXULONG_PTR) + ImageSectionObject->ImageBase = EXEFMT_LOAD_BASE_NONE; + /* Position-independent image, base address doesn't matter */ + else if(nImageBase == 0) + ImageSectionObject->ImageBase = EXEFMT_LOAD_BASE_ANY; + /* Use the specified base address */ + else + ImageSectionObject->ImageBase = (ULONG_PTR)nImageBase; + + /* safest bet */ + ImageSectionObject->Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI; + ImageSectionObject->MinorSubsystemVersion = 0; + ImageSectionObject->MajorSubsystemVersion = 4; + + /* Success, at last */ + nStatus = STATUS_SUCCESS; + +l_Return: + if(pBuffer) + ExFreePool(pBuffer); + + return nStatus; +} + +/* EOF */ diff --git a/reactos/ntoskrnl/mm/elf32.c b/reactos/ntoskrnl/mm/elf32.c new file mode 100644 index 00000000000..0a4374171f1 --- /dev/null +++ b/reactos/ntoskrnl/mm/elf32.c @@ -0,0 +1,145 @@ +#define __ELF_WORD_SIZE 32 +#include "elf.c" + +extern NTSTATUS NTAPI Elf64FmtCreateSection +( + IN CONST VOID * FileHeader, + IN SIZE_T FileHeaderSize, + IN PVOID File, + OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject, + OUT PULONG Flags, + IN PEXEFMT_CB_READ_FILE ReadFileCb, + IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb +); + +NTSTATUS NTAPI ElfFmtCreateSection +( + IN CONST VOID * FileHeader, + IN SIZE_T FileHeaderSize, + IN PVOID File, + OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject, + OUT PULONG Flags, + IN PEXEFMT_CB_READ_FILE ReadFileCb, + IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb +) +{ + ULONG nDataType; + const Elf32_Ehdr * pehTempHeader; + + ASSERT(FileHeader); + ASSERT(FileHeaderSize > 0); + ASSERT(Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize)); + ASSERT(File); + ASSERT(ImageSectionObject); + ASSERT(Flags); + ASSERT(ReadFileCb); + ASSERT(AllocateSegmentsCb); + + pehTempHeader = FileHeader; + ASSERT(((ULONG_PTR)pehTempHeader % TYPE_ALIGNMENT(Elf32_Ehdr)) == 0); + ASSERT(((ULONG_PTR)pehTempHeader % TYPE_ALIGNMENT(Elf64_Ehdr)) == 0); + + ASSERT(ELFFMT_FIELDS_EQUAL(Elf32_Ehdr, Elf64_Ehdr, e_ident)); + + /* File too small to be identified */ + if(!RTL_CONTAINS_FIELD(pehTempHeader, FileHeaderSize, e_ident[EI_MAG3])) + return STATUS_ROS_EXEFMT_UNKNOWN_FORMAT; + + /* Not an ELF file */ + if + ( + pehTempHeader->e_ident[EI_MAG0] != ELFMAG0 || + pehTempHeader->e_ident[EI_MAG1] != ELFMAG1 || + pehTempHeader->e_ident[EI_MAG2] != ELFMAG2 || + pehTempHeader->e_ident[EI_MAG3] != ELFMAG3 + ) + return STATUS_ROS_EXEFMT_UNKNOWN_FORMAT; + + /* Validate the data type */ + nDataType = pehTempHeader->e_ident[EI_DATA]; + + switch(nDataType) + { + case ELFDATA2LSB: + case ELFDATA2MSB: + break; + + default: + return STATUS_INVALID_IMAGE_FORMAT; + } + + /* Validate the version */ + ASSERT(ELFFMT_FIELDS_EQUAL(Elf32_Ehdr, Elf64_Ehdr, e_version)); + + if + ( + pehTempHeader->e_ident[EI_VERSION] != EV_CURRENT || + ElfFmtpReadULong(pehTempHeader->e_version, nDataType) != EV_CURRENT + ) + return STATUS_INVALID_IMAGE_FORMAT; + + /* Validate the file type */ + ASSERT(ELFFMT_FIELDS_EQUAL(Elf32_Ehdr, Elf64_Ehdr, e_type)); + + switch(ElfFmtpReadUShort(pehTempHeader->e_type, nDataType)) + { + case ET_DYN: ImageSectionObject->ImageCharacteristics |= IMAGE_FILE_DLL; + case ET_EXEC: break; + default: return STATUS_INVALID_IMAGE_FORMAT; + } + + /* Convert the target machine */ + ASSERT(ELFFMT_FIELDS_EQUAL(Elf32_Ehdr, Elf64_Ehdr, e_machine)); + ASSERT(ImageSectionObject->Machine == IMAGE_FILE_MACHINE_UNKNOWN); + + switch(ElfFmtpReadUShort(pehTempHeader->e_machine, nDataType)) + { + case EM_386: ImageSectionObject->Machine = IMAGE_FILE_MACHINE_I386; break; + case EM_MIPS_RS3_LE: ImageSectionObject->Machine = IMAGE_FILE_MACHINE_R3000; break; + +#if 0 + /* TODO: need to read e_flags for full identification */ + case EM_SH: break; +#endif + + case EM_ARM: ImageSectionObject->Machine = IMAGE_FILE_MACHINE_ARM; break; + case EM_PPC: ImageSectionObject->Machine = IMAGE_FILE_MACHINE_POWERPC; break; + case EM_IA_64: ImageSectionObject->Machine = IMAGE_FILE_MACHINE_IA64; break; + case EM_ALPHA: ImageSectionObject->Machine = IMAGE_FILE_MACHINE_AXP64; break; + case EM_X86_64: ImageSectionObject->Machine = IMAGE_FILE_MACHINE_AMD64; break; + case EM_M32R: ImageSectionObject->Machine = IMAGE_FILE_MACHINE_M32R; break; + } + + /* Call the appropriate handler for the class-specific fields */ + switch(pehTempHeader->e_ident[EI_CLASS]) + { + case ELFCLASS32: + return Elf32FmtCreateSection + ( + FileHeader, + FileHeaderSize, + File, + ImageSectionObject, + Flags, + ReadFileCb, + AllocateSegmentsCb + ); + + case ELFCLASS64: + return Elf64FmtCreateSection + ( + FileHeader, + FileHeaderSize, + File, + ImageSectionObject, + Flags, + ReadFileCb, + AllocateSegmentsCb + ); + } + + /* Unknown class */ + return STATUS_INVALID_IMAGE_FORMAT; +} + +/* EOF */ diff --git a/reactos/ntoskrnl/mm/elf64.c b/reactos/ntoskrnl/mm/elf64.c new file mode 100644 index 00000000000..c96d87fb7aa --- /dev/null +++ b/reactos/ntoskrnl/mm/elf64.c @@ -0,0 +1,2 @@ +#define __ELF_WORD_SIZE 64 +#include "elf.c" diff --git a/reactos/ntoskrnl/mm/pe.c b/reactos/ntoskrnl/mm/pe.c new file mode 100644 index 00000000000..aceca81a6d2 --- /dev/null +++ b/reactos/ntoskrnl/mm/pe.c @@ -0,0 +1,745 @@ +/* + * ReactOS kernel + * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* $Id: pe.c,v 1.2 2004/12/30 05:59:11 hyperion Exp $ + * + * PROJECT: ReactOS kernel + * FILE: ntoskrnl/mm/pe.c + * PURPOSE: Loader for PE executables + * PROGRAMMER: KJK::Hyperion + * UPDATE HISTORY: + * 2004-12-06 Created + * 2004-12-09 Compiles + * 2004-12-26 Actually works, several checks relaxed to support + * the majority of existing executables, corrected + * the alignment helper functions, debug messages to + * explain failure. + */ + +/* INCLUDES *****************************************************************/ + +#include + +#define NDEBUG +#include + +#include + +static ULONG SectionCharacteristicsToProtect[16] = +{ + PAGE_NOACCESS, /* 0 = NONE */ + PAGE_NOACCESS, /* 1 = SHARED */ + PAGE_EXECUTE, /* 2 = EXECUTABLE */ + PAGE_EXECUTE, /* 3 = EXECUTABLE, SHARED */ + PAGE_READONLY, /* 4 = READABLE */ + PAGE_READONLY, /* 5 = READABLE, SHARED */ + PAGE_EXECUTE_READ, /* 6 = READABLE, EXECUTABLE */ + PAGE_EXECUTE_READ, /* 7 = READABLE, EXECUTABLE, SHARED */ + /* + * FIXME? do we really need the WriteCopy field in segments? can't we use + * PAGE_WRITECOPY here? + */ + PAGE_READWRITE, /* 8 = WRITABLE */ + PAGE_READWRITE, /* 9 = WRITABLE, SHARED */ + PAGE_EXECUTE_READWRITE, /* 10 = WRITABLE, EXECUTABLE */ + PAGE_EXECUTE_READWRITE, /* 11 = WRITABLE, EXECUTABLE, SHARED */ + PAGE_READWRITE, /* 12 = WRITABLE, READABLE */ + PAGE_READWRITE, /* 13 = WRITABLE, READABLE, SHARED */ + PAGE_EXECUTE_READWRITE, /* 14 = WRITABLE, READABLE, EXECUTABLE */ + PAGE_EXECUTE_READWRITE, /* 15 = WRITABLE, READABLE, EXECUTABLE, SHARED */ +}; + +/* TODO: Intsafe should be made into a library, as it's generally useful */ +static __inline BOOLEAN Intsafe_CanAddULongPtr +( + IN ULONG_PTR Addend1, + IN ULONG_PTR Addend2 +) +{ + return Addend1 <= (MAXULONG_PTR - Addend2); +} + +static __inline BOOLEAN Intsafe_CanAddULong32 +( + IN ULONG Addend1, + IN ULONG Addend2 +) +{ + return Addend1 <= (MAXULONG - Addend2); +} + +static __inline BOOLEAN Intsafe_AddULong32 +( + OUT PULONG Result, + IN ULONG Addend1, + IN ULONG Addend2 +) +{ + if(!Intsafe_CanAddULong32(Addend1, Addend2)) + return FALSE; + + *Result = Addend1 + Addend2; + return TRUE; +} + +static __inline BOOLEAN Intsafe_CanMulULong32 +( + IN ULONG Factor1, + IN ULONG Factor2 +) +{ + return Factor1 <= (MAXULONG / Factor2); +} + +static __inline BOOLEAN Intsafe_CanOffsetPointer +( + IN CONST VOID * Pointer, + IN SIZE_T Offset +) +{ + /* FIXME: (PVOID)MAXULONG_PTR isn't necessarily a valid address */ + return Intsafe_CanAddULongPtr((ULONG_PTR)Pointer, Offset); +} + +/* TODO: these are standard DDK/PSDK macros */ +#ifndef RTL_FIELD_SIZE +#define RTL_FIELD_SIZE(TYPE_, FIELD_) (sizeof(((TYPE_ *)0)->FIELD_)) +#endif + +#ifndef RTL_SIZEOF_THROUGH_FIELD +#define RTL_SIZEOF_THROUGH_FIELD(TYPE_, FIELD_) \ + (FIELD_OFFSET(TYPE_, FIELD_) + RTL_FIELD_SIZE(TYPE_, FIELD_)) +#endif + +#ifndef RTL_CONTAINS_FIELD +#define RTL_CONTAINS_FIELD(P_, SIZE_, FIELD_) \ + ((((char *)(P_)) + (SIZE_)) > (((char *)(&((P_)->FIELD_))) + sizeof((P_)->FIELD_))) +#endif + +static __inline BOOLEAN IsPowerOf2(IN ULONG Number) +{ + if(Number == 0) + return FALSE; + + while((Number % 2) == 0) + Number /= 2; + + return Number == 1; +} + +static __inline ULONG ModPow2(IN ULONG Address, IN ULONG Alignment) +{ + ASSERT(IsPowerOf2(Alignment)); + return Address & (Alignment - 1); +} + +static __inline BOOLEAN IsAligned(IN ULONG Address, IN ULONG Alignment) +{ + return ModPow2(Address, Alignment) == 0; +} + +static __inline BOOLEAN AlignUp +( + OUT PULONG AlignedAddress, + IN ULONG Address, + IN ULONG Alignment +) +{ + ULONG nExcess = ModPow2(Address, Alignment); + + if(nExcess == 0) + { + *AlignedAddress = Address; + return nExcess == 0; + } + else + return Intsafe_AddULong32(AlignedAddress, Address, Alignment - nExcess); +} + +#define PEFMT_FIELDS_EQUAL(TYPE1_, TYPE2_, FIELD_) \ + ( \ + (FIELD_OFFSET(TYPE1_, FIELD_) == FIELD_OFFSET(TYPE2_, FIELD_)) && \ + (RTL_FIELD_SIZE(TYPE1_, FIELD_) == RTL_FIELD_SIZE(TYPE2_, FIELD_)) \ + ) + +/* + References: + [1] Microsoft Corporation, "Microsoft Portable Executable and Common Object + File Format Specification", revision 6.0 (February 1999) +*/ +NTSTATUS NTAPI PeFmtCreateSection +( + IN CONST VOID * FileHeader, + IN SIZE_T FileHeaderSize, + IN PVOID File, + OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject, + OUT PULONG Flags, + IN PEXEFMT_CB_READ_FILE ReadFileCb, + IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb +) +{ + NTSTATUS nStatus; + ULONG cbFileHeaderOffsetSize; + ULONG cbSectionHeadersOffset; + ULONG cbSectionHeadersSize; + ULONG cbSectionHeadersOffsetSize; + ULONG cbOptHeaderSize; + ULONG cbHeadersSize; + ULONG nSectionAlignment; + ULONG nFileAlignment; + const IMAGE_DOS_HEADER * pidhDosHeader; + const IMAGE_NT_HEADERS32 * pinhNtHeader; + const IMAGE_OPTIONAL_HEADER32 * piohOptHeader; + const IMAGE_SECTION_HEADER * pishSectionHeaders; + PMM_SECTION_SEGMENT pssSegments; + LARGE_INTEGER lnOffset; + PVOID pBuffer; + ULONG nPrevVirtualEndOfSegment; + ULONG nPrevFileEndOfSegment; + ULONG i; + + ASSERT(FileHeader); + ASSERT(FileHeaderSize > 0); + ASSERT(File); + ASSERT(ImageSectionObject); + ASSERT(ReadFileCb); + ASSERT(AllocateSegmentsCb); + + ASSERT(Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize)); + + ASSERT(FileHeaderSize >= sizeof(IMAGE_DOS_HEADER)); + ASSERT(((UINT_PTR)FileHeader % TYPE_ALIGNMENT(IMAGE_DOS_HEADER)) == 0); + +#define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; } + + pBuffer = NULL; + pidhDosHeader = FileHeader; + + /* DOS HEADER */ + nStatus = STATUS_ROS_EXEFMT_UNKNOWN_FORMAT; + + /* no MZ signature */ + if(pidhDosHeader->e_magic != IMAGE_DOS_SIGNATURE) + DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader->e_magic)); + + /* not a Windows executable */ + if(pidhDosHeader->e_lfanew <= 0) + DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader->e_lfanew)); + + /* NT HEADER */ + nStatus = STATUS_INVALID_IMAGE_FORMAT; + + if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize, pidhDosHeader->e_lfanew, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32, FileHeader))) + DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader->e_lfanew)); + + if(FileHeaderSize < cbFileHeaderOffsetSize) + pinhNtHeader = NULL; + else + { + /* + we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize), + and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too + */ + ASSERT(Intsafe_CanOffsetPointer(FileHeader, pidhDosHeader->e_lfanew)); + pinhNtHeader = (PVOID)((UINT_PTR)FileHeader + pidhDosHeader->e_lfanew); + } + + ASSERT(sizeof(IMAGE_NT_HEADERS32) <= sizeof(IMAGE_NT_HEADERS64)); + ASSERT(TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) == TYPE_ALIGNMENT(IMAGE_NT_HEADERS64)); + ASSERT(RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32, FileHeader) == RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS64, FileHeader)); + ASSERT(FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader) == FIELD_OFFSET(IMAGE_NT_HEADERS64, OptionalHeader)); + + /* + the buffer doesn't contain the NT file header, or the alignment is wrong: we + need to read the header from the file + */ + if + ( + FileHeaderSize < cbFileHeaderOffsetSize || + (UINT_PTR)pinhNtHeader % TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) != 0 + ) + { + ULONG cbNtHeaderSize; + ULONG cbReadSize; + PVOID pData; + +l_ReadHeaderFromFile: + lnOffset.QuadPart = pidhDosHeader->e_lfanew; + + /* read the header from the file */ + nStatus = ReadFileCb + ( + File, + &lnOffset, + sizeof(IMAGE_NT_HEADERS64), + &pData, + &pBuffer, + &cbReadSize + ); + + if(!NT_SUCCESS(nStatus)) + DIE(("ReadFile failed, status %08X\n", nStatus)); + + ASSERT(pData); + ASSERT(pBuffer); + ASSERT(cbReadSize > 0); + + nStatus = STATUS_INVALID_IMAGE_FORMAT; + + /* the buffer doesn't contain the file header */ + if(cbReadSize < RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32, FileHeader)) + DIE(("The file doesn't contain the PE file header\n")); + + pinhNtHeader = pData; + + /* object still not aligned: copy it to the beginning of the buffer */ + if((UINT_PTR)pinhNtHeader % TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) != 0) + { + ASSERT((UINT_PTR)pBuffer % TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) == 0); + RtlMoveMemory(pBuffer, pData, cbReadSize); + pinhNtHeader = pBuffer; + } + + /* invalid NT header */ + if(pinhNtHeader->Signature != IMAGE_NT_SIGNATURE) + DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader->Signature)); + + if(!Intsafe_AddULong32(&cbNtHeaderSize, pinhNtHeader->FileHeader.SizeOfOptionalHeader, FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader))) + DIE(("The full NT header is too large\n")); + + nStatus = STATUS_UNSUCCESSFUL; + + /* the buffer doesn't contain the whole NT header */ + if(cbReadSize < cbNtHeaderSize) + DIE(("The file doesn't contain the full NT header\n")); + } + else + { + SIZE_T cbOptHeaderOffsetSize; + + nStatus = STATUS_INVALID_IMAGE_FORMAT; + + /* don't trust an invalid NT header */ + if(pinhNtHeader->Signature != IMAGE_NT_SIGNATURE) + DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader->Signature)); + + if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize, pidhDosHeader->e_lfanew, FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader))) + DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader->e_lfanew)); + + if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize, cbOptHeaderOffsetSize, pinhNtHeader->FileHeader.SizeOfOptionalHeader)) + DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader->FileHeader.SizeOfOptionalHeader)); + + /* the buffer doesn't contain the whole NT header: read it from the file */ + if(cbOptHeaderOffsetSize > FileHeaderSize) + goto l_ReadHeaderFromFile; + } + + /* read information from the NT header */ + piohOptHeader = &pinhNtHeader->OptionalHeader; + cbOptHeaderSize = pinhNtHeader->FileHeader.SizeOfOptionalHeader; + + nStatus = STATUS_INVALID_IMAGE_FORMAT; + + ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, Magic)); + + if(!RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, Magic)) + DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize)); + + /* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */ + + switch(piohOptHeader->Magic) + { + case IMAGE_NT_OPTIONAL_HDR32_MAGIC: + case IMAGE_NT_OPTIONAL_HDR64_MAGIC: + break; + + default: + DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader->Magic)); + } + + ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, SectionAlignment)); + ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, FileAlignment)); + + if + ( + RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SectionAlignment) && + RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, FileAlignment) + ) + { + /* See [1], section 3.4.2 */ + if(piohOptHeader->SectionAlignment < PAGE_SIZE) + { + if(piohOptHeader->FileAlignment != piohOptHeader->SectionAlignment) + DIE(("Sections aren't page-aligned and the file alignment isn't the same\n")); + } + else if(piohOptHeader->SectionAlignment < piohOptHeader->FileAlignment) + DIE(("The section alignment is smaller than the file alignment\n")); + + nSectionAlignment = piohOptHeader->SectionAlignment; + nFileAlignment = piohOptHeader->FileAlignment; + + if(!IsPowerOf2(nSectionAlignment) || !IsPowerOf2(nFileAlignment)) + DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment, nFileAlignment)); + } + else + { + nSectionAlignment = PAGE_SIZE; + nFileAlignment = PAGE_SIZE; + } + + ASSERT(IsPowerOf2(nSectionAlignment)); + ASSERT(IsPowerOf2(nFileAlignment)); + + switch(piohOptHeader->Magic) + { + /* PE32 */ + case IMAGE_NT_OPTIONAL_HDR32_MAGIC: + { + if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, ImageBase)) + ImageSectionObject->ImageBase = piohOptHeader->ImageBase; + + if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfStackReserve)) + ImageSectionObject->StackReserve = piohOptHeader->SizeOfStackReserve; + + if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfStackCommit)) + ImageSectionObject->StackCommit = piohOptHeader->SizeOfStackCommit; + + break; + } + + /* PE32+ */ + case IMAGE_NT_OPTIONAL_HDR64_MAGIC: + { + const IMAGE_OPTIONAL_HEADER64 * pioh64OptHeader; + + pioh64OptHeader = (const IMAGE_OPTIONAL_HEADER64 *)piohOptHeader; + + if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, ImageBase)) + { + if(pioh64OptHeader->ImageBase > MAXULONG_PTR) + DIE(("ImageBase exceeds the address space\n")); + + ImageSectionObject->ImageBase = pioh64OptHeader->ImageBase; + } + + if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfStackReserve)) + { + if(pioh64OptHeader->SizeOfStackReserve > MAXULONG_PTR) + DIE(("SizeOfStackReserve exceeds the address space\n")); + + ImageSectionObject->StackReserve = pioh64OptHeader->SizeOfStackReserve; + } + + if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfStackCommit)) + { + if(pioh64OptHeader->SizeOfStackCommit > MAXULONG_PTR) + DIE(("SizeOfStackCommit exceeds the address space\n")); + + ImageSectionObject->StackCommit = pioh64OptHeader->SizeOfStackCommit; + } + + break; + } + } + + /* [1], section 3.4.2 */ + if((ULONG_PTR)ImageSectionObject->ImageBase % 0x10000) + DIE(("ImageBase is not aligned on a 64KB boundary")); + + ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, Subsystem)); + ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, MinorSubsystemVersion)); + ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, MajorSubsystemVersion)); + + if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, Subsystem)) + { + ImageSectionObject->Subsystem = piohOptHeader->Subsystem; + + if + ( + RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, MinorSubsystemVersion) && + RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, MajorSubsystemVersion) + ) + { + ImageSectionObject->MinorSubsystemVersion = piohOptHeader->MinorSubsystemVersion; + ImageSectionObject->MajorSubsystemVersion = piohOptHeader->MajorSubsystemVersion; + } + } + + ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, AddressOfEntryPoint)); + + if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, AddressOfEntryPoint)) + ImageSectionObject->EntryPoint = piohOptHeader->AddressOfEntryPoint; + + ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, SizeOfCode)); + + if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfCode)) + ImageSectionObject->Executable = piohOptHeader->SizeOfCode != 0; + else + ImageSectionObject->Executable = TRUE; + + ImageSectionObject->ImageCharacteristics = pinhNtHeader->FileHeader.Characteristics; + ImageSectionObject->Machine = pinhNtHeader->FileHeader.Machine; + + /* SECTION HEADERS */ + nStatus = STATUS_INVALID_IMAGE_FORMAT; + + /* see [1], section 3.3 */ + if(pinhNtHeader->FileHeader.NumberOfSections > 96) + DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader->FileHeader.NumberOfSections)); + + /* + the additional segment is for the file's headers. They need to be present for + the benefit of the dynamic loader (to locate exports, defaults for thread + parameters, resources, etc.) + */ + ImageSectionObject->NrSegments = pinhNtHeader->FileHeader.NumberOfSections + 1; + + /* file offset for the section headers */ + if(!Intsafe_AddULong32(&cbSectionHeadersOffset, pidhDosHeader->e_lfanew, FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader))) + DIE(("Offset overflow\n")); + + if(!Intsafe_AddULong32(&cbSectionHeadersOffset, cbSectionHeadersOffset, pinhNtHeader->FileHeader.SizeOfOptionalHeader)) + DIE(("Offset overflow\n")); + + /* size of the section headers */ + ASSERT(Intsafe_CanMulULong32(pinhNtHeader->FileHeader.NumberOfSections, sizeof(IMAGE_SECTION_HEADER))); + cbSectionHeadersSize = pinhNtHeader->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER); + + if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize, cbSectionHeadersOffset, cbSectionHeadersSize)) + DIE(("Section headers too large\n")); + + ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, SizeOfHeaders)); + + /* size of the executable's headers */ + if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfHeaders)) + { + if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment)) + DIE(("SizeOfHeaders is not aligned\n")); + + if(cbSectionHeadersSize > piohOptHeader->SizeOfHeaders) + DIE(("The section headers overflow SizeOfHeaders\n")); + + cbHeadersSize = piohOptHeader->SizeOfHeaders; + } + else if(!AlignUp(&cbHeadersSize, cbSectionHeadersOffsetSize, nFileAlignment)) + DIE(("Overflow aligning the size of headers\n")); + + if(pBuffer) + { + ExFreePool(pBuffer); + pBuffer = NULL; + } + /* WARNING: pinhNtHeader IS NO LONGER USABLE */ + /* WARNING: piohOptHeader IS NO LONGER USABLE */ + /* WARNING: pioh64OptHeader IS NO LONGER USABLE */ + + if(FileHeaderSize < cbSectionHeadersOffsetSize) + pishSectionHeaders = NULL; + else + { + /* + we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize), + and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too + */ + ASSERT(Intsafe_CanOffsetPointer(FileHeader, cbSectionHeadersOffset)); + pishSectionHeaders = (PVOID)((UINT_PTR)FileHeader + cbSectionHeadersOffset); + } + + /* + the buffer doesn't contain the section headers, or the alignment is wrong: + read the headers from the file + */ + if + ( + FileHeaderSize < cbSectionHeadersOffsetSize || + (UINT_PTR)pishSectionHeaders % TYPE_ALIGNMENT(IMAGE_SECTION_HEADER) != 0 + ) + { + PVOID pData; + ULONG cbReadSize; + + lnOffset.QuadPart = cbSectionHeadersOffset; + + /* read the header from the file */ + nStatus = ReadFileCb + ( + File, + &lnOffset, + cbSectionHeadersSize, + &pData, + &pBuffer, + &cbReadSize + ); + + if(!NT_SUCCESS(nStatus)) + DIE(("ReadFile failed with status %08X\n", nStatus)); + + ASSERT(pData); + ASSERT(pBuffer); + ASSERT(cbReadSize > 0); + + nStatus = STATUS_INVALID_IMAGE_FORMAT; + + /* the buffer doesn't contain all the section headers */ + if(cbReadSize < cbSectionHeadersSize) + DIE(("The file doesn't contain all of the section headers\n")); + + pishSectionHeaders = pData; + + /* object still not aligned: copy it to the beginning of the buffer */ + if((UINT_PTR)pishSectionHeaders % TYPE_ALIGNMENT(IMAGE_SECTION_HEADER) != 0) + { + ASSERT((UINT_PTR)pBuffer % TYPE_ALIGNMENT(IMAGE_SECTION_HEADER) == 0); + RtlMoveMemory(pBuffer, pData, cbReadSize); + pishSectionHeaders = pBuffer; + } + } + + /* SEGMENTS */ + /* allocate the segments */ + nStatus = STATUS_INSUFFICIENT_RESOURCES; + ImageSectionObject->Segments = AllocateSegmentsCb(ImageSectionObject->NrSegments); + + if(ImageSectionObject->Segments == NULL) + DIE(("AllocateSegments failed\n")); + + /* initialize the headers segment */ + pssSegments = ImageSectionObject->Segments; + + ASSERT(IsAligned(cbHeadersSize, nFileAlignment)); + + if(!AlignUp(&nPrevFileEndOfSegment, cbHeadersSize, nFileAlignment)) + DIE(("Cannot align the size of the section headers\n")); + + if(!AlignUp(&nPrevVirtualEndOfSegment, cbHeadersSize, nSectionAlignment)) + DIE(("Cannot align the size of the section headers\n")); + + pssSegments[0].FileOffset = 0; + pssSegments[0].Protection = PAGE_READONLY; + pssSegments[0].Length = nPrevVirtualEndOfSegment; + pssSegments[0].RawLength = nPrevFileEndOfSegment; + pssSegments[0].VirtualAddress = 0; + pssSegments[0].Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA; + pssSegments[0].WriteCopy = TRUE; + + /* skip the headers segment */ + ++ pssSegments; + + nStatus = STATUS_INVALID_IMAGE_FORMAT; + + /* convert the executable sections into segments. See also [1], section 4 */ + for(i = 0; i < ImageSectionObject->NrSegments - 1; ++ i) + { + ULONG nCharacteristics; + + /* validate the alignment */ + if(!IsAligned(pishSectionHeaders[i].VirtualAddress, nSectionAlignment)) + DIE(("VirtualAddress[%u] is not aligned\n", i)); + + /* sections must be contiguous, ordered by base address and non-overlapping */ + if(pishSectionHeaders[i].VirtualAddress != nPrevVirtualEndOfSegment) + DIE(("Memory gap between section %u and the previous\n", i)); + + /* ignore explicit BSS sections */ + if(pishSectionHeaders[i].SizeOfRawData != 0) + { + /* validate the alignment */ + if(!IsAligned(pishSectionHeaders[i].SizeOfRawData, nFileAlignment)) + DIE(("SizeOfRawData[%u] is not aligned\n", i)); + + if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment)) + DIE(("PointerToRawData[%u] is not aligned\n", i)); + + /* sections must be contiguous, ordered by base address and non-overlapping */ + if(pishSectionHeaders[i].PointerToRawData != nPrevFileEndOfSegment) + DIE(("File gap between section %u and the previous\n", i)); + + /* conversion */ + pssSegments[i].FileOffset = pishSectionHeaders[i].PointerToRawData; + pssSegments[i].RawLength = pishSectionHeaders[i].SizeOfRawData; + } + else + { + ASSERT(pssSegments[i].FileOffset == 0); + ASSERT(pssSegments[i].RawLength == 0); + } + + nCharacteristics = pishSectionHeaders[i].Characteristics; + + /* no explicit protection */ + if((nCharacteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)) == 0) + { + if(nCharacteristics & IMAGE_SCN_CNT_CODE) + nCharacteristics |= IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ; + + if(nCharacteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) + nCharacteristics |= IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE; + + if(nCharacteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) + nCharacteristics |= IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE; + } + + /* see table above */ + pssSegments[i].Protection = SectionCharacteristicsToProtect[nCharacteristics >> 28]; + pssSegments[i].WriteCopy = !(nCharacteristics & IMAGE_SCN_MEM_SHARED); + + if(pishSectionHeaders[i].Misc.VirtualSize == 0 || pishSectionHeaders[i].Misc.VirtualSize < pishSectionHeaders[i].SizeOfRawData) + pssSegments[i].Length = pishSectionHeaders[i].SizeOfRawData; + else + pssSegments[i].Length = pishSectionHeaders[i].Misc.VirtualSize; + + if(!AlignUp(&pssSegments[i].Length, pssSegments[i].Length, nSectionAlignment)) + DIE(("Cannot align the virtual size of section %u\n", i)); + + ASSERT(IsAligned(pssSegments[i].Length, nSectionAlignment)); + + if(pssSegments[i].Length == 0) + DIE(("Virtual size of section %u is null\n", i)); + + pssSegments[i].VirtualAddress = pishSectionHeaders[i].VirtualAddress; + pssSegments[i].Characteristics = pishSectionHeaders[i].Characteristics; + + /* ensure the executable is no larger than 4GB */ + if(pssSegments[i].RawLength != 0) + { + if(!Intsafe_AddULong32(&nPrevFileEndOfSegment, pssSegments[i].FileOffset, pssSegments[i].RawLength)) + DIE(("The executable is larger than 4GB\n")); + } + + /* ensure the memory image is no larger than 4GB */ + if(!Intsafe_AddULong32(&nPrevVirtualEndOfSegment, pssSegments[i].VirtualAddress, pssSegments[i].Length)) + DIE(("The image is larger than 4GB\n")); + } + + /* spare our caller some work in validating the segments */ + *Flags = EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED | EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP; + + if(nSectionAlignment >= PAGE_SIZE) + *Flags |= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED; + + /* Success */ + nStatus = STATUS_ROS_EXEFMT_LOADED_FORMAT & EXEFMT_LOADED_PE32; + +l_Return: + if(pBuffer) + ExFreePool(pBuffer); + + return nStatus; +} + +/* EOF */