├── src ├── macho.h ├── stdafx.cpp ├── build.sh ├── stdafx.h ├── error.h ├── maindef.h ├── library.h ├── objconv.vcproj ├── cmdline.h ├── cof2cof.cpp ├── omf.h ├── error.cpp ├── mac2mac.cpp ├── elf2elf.cpp ├── omfhash.cpp ├── containers.h ├── elf2asm.cpp └── elf.cpp ├── extras ├── w2ustub.o ├── u2wstub.obj ├── w2ustubvec.o ├── u2wstubvec1.obj ├── u2wstubvec2.obj ├── w2ustub.asm ├── w2ustubvec.asm ├── u2wstubvec1.asm ├── u2wstub.asm └── u2wstubvec2.asm ├── objconv-instructions.pdf └── README.md /src/macho.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vertis/objconv/HEAD/src/macho.h -------------------------------------------------------------------------------- /extras/w2ustub.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vertis/objconv/HEAD/extras/w2ustub.o -------------------------------------------------------------------------------- /extras/u2wstub.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vertis/objconv/HEAD/extras/u2wstub.obj -------------------------------------------------------------------------------- /extras/w2ustubvec.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vertis/objconv/HEAD/extras/w2ustubvec.o -------------------------------------------------------------------------------- /extras/u2wstubvec1.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vertis/objconv/HEAD/extras/u2wstubvec1.obj -------------------------------------------------------------------------------- /extras/u2wstubvec2.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vertis/objconv/HEAD/extras/u2wstubvec2.obj -------------------------------------------------------------------------------- /objconv-instructions.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vertis/objconv/HEAD/objconv-instructions.pdf -------------------------------------------------------------------------------- /src/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // objconv.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This repo is a git mirror of http://www.agner.org/optimize/objconv.zip by Agner Fog 2 | 3 | ## Building 4 | You can build objconv with the following command (sorry no Makefile): 5 | 6 | g++ -o objconv -O2 src/*.cpp 7 | 8 | ## License 9 | It is, as mentioned in the source code, Copyright 2006-2008 GNU General Public License http://www.gnu.org/licenses -------------------------------------------------------------------------------- /src/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Build script for building objconv on Linux, BSD and Mac OS X platforms. 4 | 5 | # Instructions: 6 | 7 | # You may need to change the path to bash above as required by your system 8 | 9 | # Make sure the current directory contains all the .cpp files for objconv, 10 | # and only one copy of each, and no other .cpp files 11 | 12 | # Then run ./build.sh 13 | # The compilation may take half a minute. 14 | 15 | # Alternatively, run the following line: 16 | 17 | g++ -o objconv -O2 *.cpp -------------------------------------------------------------------------------- /src/stdafx.h: -------------------------------------------------------------------------------- 1 | /**************************** stdafx.h ********************************** 2 | * Author: Agner Fog 3 | * Date created: 2006-07-15 4 | * Last modified: 2006-07-15 5 | * Project: objconv 6 | * Module: stdafx.h 7 | * Description: 8 | * Header file including other header files for the project. 9 | * 10 | * Copyright 2006-2008 GNU General Public License http://www.gnu.org/licenses 11 | *****************************************************************************/ 12 | 13 | #ifndef OBJCONV_STDAFX_H 14 | #define OBJCONV_STDAFX_H 15 | 16 | // System header files 17 | #include 18 | #include 19 | #include 20 | #include 21 | #ifdef _MSC_VER // For Microsoft compiler only: 22 | #include // File in/out function headers 23 | #include 24 | #include 25 | #define stricmp _stricmp // For later versions of MS compiler 26 | #define strnicmp _strnicmp // For later versions of MS compiler 27 | #define filelength _filelength // For later versions of MS compiler 28 | #else // For Gnu and other compilers: 29 | #define stricmp strcasecmp // Alternative function names 30 | #define strnicmp strncasecmp 31 | #endif 32 | 33 | // Project header files. The order of these files is not arbitrary. 34 | #include "maindef.h" // Constants, integer types, etc. 35 | #include "error.h" // Error handler 36 | #include "containers.h" // Classes for data buffers and dynamic memory allocation 37 | #include "coff.h" // COFF files structure 38 | #include "elf.h" // ELF files structure 39 | #include "omf.h" // OMF files structure 40 | #include "macho.h" // Mach-O files structure 41 | #include "disasm.h" // Structures and classes for disassembler 42 | #include "converters.h" // Classes for file converters 43 | #include "library.h" // Classes for reading and writing libraries 44 | #include "cmdline.h" // Command line interpreter class 45 | 46 | #endif // defined OBJCONV_STDAFX_H 47 | -------------------------------------------------------------------------------- /src/error.h: -------------------------------------------------------------------------------- 1 | /**************************** error.h ************************************ 2 | * Author: Agner Fog 3 | * Date created: 2006-07-15 4 | * Last modified: 2006-07-15 5 | * Project: objconv 6 | * Module: error.h 7 | * Description: 8 | * Header file for error handler error.cpp 9 | * 10 | * Copyright 2006-2008 GNU General Public License http://www.gnu.org/licenses 11 | *****************************************************************************/ 12 | #ifndef OBJCONV_ERROR_H 13 | #define OBJCONV_ERROR_H 14 | 15 | // Structure for defining error message texts 16 | struct SErrorText { 17 | int ErrorNumber; // Error number 18 | int Status; // bit 0-3 = severity: 0 = ignore, 1 = warning, 2 = error, 9 = abort 19 | // bit 8 = error number not found 20 | char const * Text; // Error text 21 | }; 22 | 23 | // General error routine for reporting warning and error messages to STDERR output 24 | class CErrorReporter { 25 | public: 26 | CErrorReporter(); // Default constructor 27 | static SErrorText * FindError(int ErrorNumber); // Search for error in ErrorTexts 28 | void submit(int ErrorNumber); // Print error message 29 | void submit(int ErrorNumber, int extra); // Print error message with extra info 30 | void submit(int ErrorNumber, int, int); // Print error message with two extra numbers inserted 31 | void submit(int ErrorNumber, char const * extra); // Print error message with extra info 32 | void submit(int ErrorNumber, char const *, char const *); // Print error message with two extra text fields inserted 33 | void submit(int ErrorNumber, int, char const *); // Print error message with two extra text fields inserted 34 | int Number(); // Get number of errors 35 | int GetWorstError(); // Get highest warning or error number encountered 36 | void ClearError(int ErrorNumber); // Ignore further occurrences of this error 37 | protected: 38 | int NumErrors; // Number of errors detected 39 | int NumWarnings; // Number of warnings detected 40 | int WorstError; // Highest error number encountered 41 | int MaxWarnings; // Max number of warning messages to pring 42 | int MaxErrors; // Max number of error messages to print 43 | void HandleError(SErrorText * err, char const * text); // Used by submit function 44 | }; 45 | 46 | #ifndef OBJCONV_ERROR_CPP 47 | extern CErrorReporter err; // Error handling object is in error.cpp 48 | extern SErrorText ErrorTexts[]; // List of error texts 49 | #endif 50 | 51 | #endif // #ifndef OBJCONV_ERROR_H 52 | -------------------------------------------------------------------------------- /extras/w2ustub.asm: -------------------------------------------------------------------------------- 1 | ; ***************************** w2ustub.asm ******************************** 2 | ; Author: Agner Fog 3 | ; Date created: 2009-05-27 4 | ; 5 | ; Description: 6 | ; Call stub for calling 64-bit Windows functions from Linux, BSD or Mac 7 | ; 8 | ; (c) 2009 GNU General Public License www.gnu.org/copyleft/gpl.html 9 | ; ***************************************************************************** 10 | ; 11 | ; This call stub takes care of the differences between the calling conventions 12 | ; of 64-bit Windows and 64-bit Unix systems (Linux, BSD, Mac OS X) when a 13 | ; function compiled for 64-bit Windows is called in a Unix system. No stub is 14 | ; needed in 32-bit systems. 15 | ; 16 | ; See the manual for instructions 17 | ; 18 | ; Requirements: 19 | ; The converted function must meet the following requirements: 20 | ; 21 | ; * Must not call any system functions or any library functions or 22 | ; access any data not available on the target system. 23 | ; 24 | ; * Must have no more than 4 parameters. 25 | ; 26 | ; * The parameters cannot be a composite type (struct, class), but 27 | ; pointers and references to composite types are allowed. 28 | ; 29 | ; * If any parameters are of type float or double then there can be 30 | ; no parameters of any other type than float and double. 31 | ; 32 | ; * Cannot have a variable number of parameter, such as printf 33 | ; 34 | ; * The return can be void or any type. If the return is a composite type 35 | ; then this may use a return pointer, counting as one parameter. 36 | ; 37 | ; * The function should preferably have extern "C" declaration in both 38 | ; systems. If the declaration is not extern "C" then the mangled names 39 | ; must be translated manually. 40 | ; 41 | ; If the function has more than four parameters or a mixture of floating 42 | ; point and non-floating point parameters then you have to make your own 43 | ; stub assembler code to account for the differences in parameter transfer 44 | ; methods. 45 | ; 46 | ; If the converted Windows function calls another converted Windows function 47 | ; then no stub is needed for the latter call. If the converted Windows 48 | ; function calls a Unix function then the call must go through a reverse 49 | ; stub created from u2wstub. 50 | ; 51 | ; See www.agner.org/optimize/calling_conventions.pdf for further details 52 | ; about differences in calling conventions. 53 | ; **************************************************************************** 54 | 55 | .code 56 | 57 | extern wname: near 58 | 59 | uname proc ; call from Unix goes here 60 | 61 | ; Unix parameters (rdi,rsi,rdx,rcx) -> Windows parameters (rcx,rdx,r8,r9) 62 | mov r9, rcx 63 | mov r8, rdx 64 | mov rdx, rsi 65 | mov rcx, rdi 66 | 67 | ; make 32 bytes shadow space and align by 16 68 | sub rsp, 40 69 | 70 | call wname ; Call to Windows function here 71 | 72 | ; restore stack 73 | add rsp, 40 74 | ret 75 | 76 | uname endp 77 | 78 | end 79 | -------------------------------------------------------------------------------- /extras/w2ustubvec.asm: -------------------------------------------------------------------------------- 1 | ; *************************** w2ustubvec.asm ******************************* 2 | ; Author: Agner Fog 3 | ; Date created: 2008-06-03 4 | ; 5 | ; Description: 6 | ; Call stub for calling 64-bit Windows functions from Linux, BSD or Mac 7 | ; with up to four vector parameters. 8 | ; 9 | ; (c) 2008 GNU General Public License www.gnu.org/copyleft/gpl.html 10 | ; ***************************************************************************** 11 | ; 12 | ; This call stub takes care of the differences between the calling conventions 13 | ; of 64-bit Windows and 64-bit Unix systems (Linux, BSD, Mac OS X) when a 14 | ; function compiled for 64-bit Windows is called in a Unix system with vector 15 | ; type parameters. No stub is needed in 32-bit systems. 16 | ; 17 | ; See the manual for instructions 18 | ; 19 | ; Requirements: 20 | ; The converted function must meet the following requirements: 21 | ; 22 | ; * Must not call any system functions or any library functions or 23 | ; access any data not available on the target system. 24 | ; 25 | ; * Must have no more than 4 parameters. 26 | ; 27 | ; * All parameters must be of type __m128, __m128i or __m128d. 28 | ; 29 | ; * No parameter can be a pointer, reference or any other type than 30 | ; the intrinsic vector types mentioned above. 31 | ; 32 | ; * The function cannot be member of a class or structure. 33 | ; 34 | ; * The return can be void or any type, except a composite type 35 | ; requiring a return pointer. 36 | ; 37 | ; * The function should preferably have extern "C" declaration in both 38 | ; systems. If the declaration is not extern "C" then the mangled names 39 | ; must be translated manually. 40 | ; 41 | ; If the function has more than four parameters or a mixture of vector 42 | ; and non-vector parameters then you have to make your own stub assembler 43 | ; code to account for the differences in parameter transfer methods. 44 | ; 45 | ; If the converted Windows function calls another converted Windows function 46 | ; then no stub is needed for the latter call. If the converted Windows 47 | ; function calls a Unix function then the call must go through a reverse 48 | ; stub created from u2wstub, u2wstubvec1 or u2wstubvec2. 49 | ; 50 | ; See www.agner.org/optimize/calling_conventions.pdf for further details 51 | ; about differences in calling conventions. 52 | ; **************************************************************************** 53 | 54 | .code 55 | 56 | extern wname: near 57 | 58 | uname proc ; call from Unix goes here 59 | 60 | ; make 64 bytes space for parameters, 32 bytes shadow space and align by 16 61 | sub rsp, 68H 62 | 63 | ; Unix parameters (xmm0, xmm1, xmm2, xmm3) -> Windows parameters ([rcx],[rdx],[r8],[r9]) 64 | lea rcx, [rsp-30H] 65 | lea rdx, [rsp-40H] 66 | lea r8, [rsp-50H] 67 | lea r9, [rsp-60H] 68 | movaps [rcx], xmm0 69 | movaps [rdx], xmm1 70 | movaps [r8], xmm2 71 | movaps [r9], xmm3 72 | 73 | call wname ; Call to Windows function here 74 | 75 | ; restore stack 76 | add rsp, 68H 77 | ret 78 | 79 | uname endp 80 | 81 | end 82 | -------------------------------------------------------------------------------- /extras/u2wstubvec1.asm: -------------------------------------------------------------------------------- 1 | ; *************************** u2wstubvec1.asm ****************************** 2 | ; Author: Agner Fog 3 | ; Date created: 2008-06-03 4 | ; 5 | ; Description: 6 | ; Call stub for calling 64-bit Linux, BSD or Mac functions from Windows 7 | ; with one vector parameter. 8 | ; 9 | ; (c) 2008 GNU General Public License www.gnu.org/copyleft/gpl.html 10 | ; ***************************************************************************** 11 | ; 12 | ; This call stub takes care of the differences between the calling conventions 13 | ; of 64-bit Windows and 64-bit Unix systems (Linux, BSD, Mac OS X) when a 14 | ; function with vector parameters compiled for a Unix system is called from 15 | ; Windows. No stub is needed in 32-bit systems. 16 | ; 17 | ; See the manual for instructions 18 | ; 19 | ; Requirements: 20 | ; The converted function must meet the following requirements: 21 | ; 22 | ; * Must not call any system functions or any library functions or 23 | ; access any data not available on the target system. 24 | ; 25 | ; * Must have exactly one parameter of type __m128, __m128i or __m128d 26 | ; 27 | ; * The parameter cannot be a pointer or reference. 28 | ; 29 | ; * The function cannot be member of a class or structure. 30 | ; 31 | ; * The return can be void or any type, except a composite type 32 | ; requiring a return pointer. 33 | ; 34 | ; * The function should preferably have extern "C" declaration in both 35 | ; systems. If the declaration is not extern "C" then the mangled names 36 | ; must be translated manually. 37 | ; 38 | ; * The function should preferably not use the red zone. Compile the Unix 39 | ; function with option -mno-red-zone if possible. If the function uses 40 | ; the red zone then it will still work in Windows most of the time, but 41 | ; it may fail with an extremely low frequency in case the system discards 42 | ; the area above the stack when it is low on memory. 43 | ; 44 | ; If the function has more than one vector parameters or a mixture of vector 45 | ; and non-vector parameters then you have to make your own stub assembler 46 | ; code to account for the differences in parameter transfer methods. 47 | ; 48 | ; If the converted Unix function calls another converted Unix function then 49 | ; no stub is needed for the latter call. If the converted Unix function calls 50 | ; a Windows function then the call must go through a reverse stub created 51 | ; from w2ustub or w2ustubvec. 52 | ; 53 | ; See www.agner.org/optimize/calling_conventions.pdf for further details 54 | ; about differences in calling conventions. 55 | ; **************************************************************************** 56 | 57 | .code 58 | 59 | extern uname: near 60 | 61 | wname proc ; call from Windows goes here 62 | 63 | ; Make space for 10 xmm registers, 2 G.P. registers, 64 | ; and align stack by 16 65 | sub rsp, 184; 10*16 + 2*8 + 8 66 | 67 | ; Register rsi, rdi and xmm6 - xmm15 have callee-save status 68 | ; in Windows, but not in Unix: 69 | mov [rsp], rsi 70 | mov [rsp+8], rdi 71 | movaps [rsp+10h], xmm6 72 | movaps [rsp+20h], xmm7 73 | movaps [rsp+30h], xmm8 74 | movaps [rsp+40h], xmm9 75 | movaps [rsp+50h], xmm10 76 | movaps [rsp+60h], xmm11 77 | movaps [rsp+70h], xmm12 78 | movaps [rsp+80h], xmm13 79 | movaps [rsp+90h], xmm14 80 | movaps [rsp+0A0h],xmm15 81 | 82 | ; Windows parameters ([rcx],[rdx],[r8],[r9]) -> Unix parameters (xmm0, xmm1, xmm2, xmm3) 83 | movaps xmm0, [rcx] ; Parameter 1 84 | ;movaps xmm1, [rdx] ; Parameter 2 85 | ;movaps xmm2, [r8] ; Parameter 3 86 | ;movaps xmm2, [r9] ; Parameter 4 87 | 88 | call uname ; Call to Unix function here 89 | 90 | ; Restore saved registers 91 | mov rsi, [rsp] 92 | mov rdi, [rsp+8] 93 | movaps xmm6, [rsp+10h] 94 | movaps xmm7, [rsp+20h] 95 | movaps xmm8, [rsp+30h] 96 | movaps xmm9, [rsp+40h] 97 | movaps xmm10, [rsp+50h] 98 | movaps xmm11, [rsp+60h] 99 | movaps xmm12, [rsp+70h] 100 | movaps xmm13, [rsp+80h] 101 | movaps xmm14, [rsp+90h] 102 | movaps xmm15, [rsp+0A0h] 103 | 104 | ; restore stack pointer 105 | add rsp, 184 106 | ret 107 | 108 | wname endp 109 | 110 | end 111 | -------------------------------------------------------------------------------- /extras/u2wstub.asm: -------------------------------------------------------------------------------- 1 | ; ***************************** u2wstub.asm ******************************** 2 | ; Author: Agner Fog 3 | ; Date created: 2008-05-25 4 | ; 5 | ; Description: 6 | ; Call stub for calling 64-bit Linux, BSD or Mac functions from Windows 7 | ; 8 | ; (c) 2008 GNU General Public License www.gnu.org/copyleft/gpl.html 9 | ; ***************************************************************************** 10 | ; 11 | ; This call stub takes care of the differences between the calling conventions 12 | ; of 64-bit Windows and 64-bit Unix systems (Linux, BSD, Mac OS X) when a 13 | ; function compiled for a Unix system is called from Windows. No stub is needed 14 | ; in 32-bit systems. 15 | ; 16 | ; See the manual for instructions 17 | ; 18 | ; Requirements: 19 | ; The converted function must meet the following requirements: 20 | ; 21 | ; * Must not call any system functions or any library functions or 22 | ; access any data not available on the target system. 23 | ; 24 | ; * Must have no more than 4 parameters. 25 | ; 26 | ; * The parameters cannot be a composite type (struct, class), but 27 | ; pointers and references to composite types are allowed. 28 | ; 29 | ; * If any parameters are of type float or double then there can be 30 | ; no parameters of any other type than float and double. 31 | ; 32 | ; * Cannot have a variable number of parameter, such as printf 33 | ; 34 | ; * The return can be void or any type. If the return is a composite type 35 | ; then this may use a return pointer, counting as one parameter. 36 | ; 37 | ; * The function should preferably have extern "C" declaration in both 38 | ; systems. If the declaration is not extern "C" then the mangled names 39 | ; must be translated manually. 40 | ; 41 | ; * The function should preferably not use the red zone. Compile the Unix 42 | ; function with option -mno-red-zone if possible. If the function uses 43 | ; the red zone then it will still work in Windows most of the time, but 44 | ; it may fail with an extremely low frequency in case the system discards 45 | ; the area above the stack when it is low on memory. 46 | ; 47 | ; If the function has more than four parameters or a mixture of floating 48 | ; point and non-floating point parameters then you have to make your own 49 | ; stub assembler code to account for the differences in parameter transfer 50 | ; methods. 51 | ; 52 | ; If the converted Unix function calls another converted Unix function then 53 | ; no stub is needed for the latter call. If the converted Unix function calls 54 | ; a Windows function then the call must go through a reverse stub created 55 | ; from w2ustub. 56 | ; 57 | ; See www.agner.org/optimize/calling_conventions.pdf for further details 58 | ; about differences in calling conventions. 59 | ; **************************************************************************** 60 | 61 | .code 62 | 63 | extern uname: near 64 | 65 | wname proc ; call from Windows goes here 66 | 67 | ; Make space for 10 xmm registers, 2 G.P. registers, 68 | ; and align stack by 16 69 | sub rsp, 184; 10*16 + 2*8 + 8 70 | 71 | ; Register rsi, rdi and xmm6 - xmm15 have callee-save status 72 | ; in Windows, but not in Unix: 73 | mov [rsp], rsi 74 | mov [rsp+8], rdi 75 | movaps [rsp+10h], xmm6 76 | movaps [rsp+20h], xmm7 77 | movaps [rsp+30h], xmm8 78 | movaps [rsp+40h], xmm9 79 | movaps [rsp+50h], xmm10 80 | movaps [rsp+60h], xmm11 81 | movaps [rsp+70h], xmm12 82 | movaps [rsp+80h], xmm13 83 | movaps [rsp+90h], xmm14 84 | movaps [rsp+0A0h],xmm15 85 | 86 | ; Windows parameters (rcx,rdx,r8,r9) -> Unix parameters (rdi,rsi,rdx,rcx) 87 | mov rdi, rcx 88 | mov rsi, rdx 89 | mov rdx, r8 90 | mov rcx, r9 91 | 92 | call uname ; Call to Unix function here 93 | 94 | ; Restore saved registers 95 | mov rsi, [rsp] 96 | mov rdi, [rsp+8] 97 | movaps xmm6, [rsp+10h] 98 | movaps xmm7, [rsp+20h] 99 | movaps xmm8, [rsp+30h] 100 | movaps xmm9, [rsp+40h] 101 | movaps xmm10, [rsp+50h] 102 | movaps xmm11, [rsp+60h] 103 | movaps xmm12, [rsp+70h] 104 | movaps xmm13, [rsp+80h] 105 | movaps xmm14, [rsp+90h] 106 | movaps xmm15, [rsp+0A0h] 107 | 108 | ; restore stack pointer 109 | add rsp, 184 110 | ret 111 | 112 | wname endp 113 | 114 | end 115 | -------------------------------------------------------------------------------- /extras/u2wstubvec2.asm: -------------------------------------------------------------------------------- 1 | ; *************************** u2wstubvec2.asm ****************************** 2 | ; Author: Agner Fog 3 | ; Date created: 2008-06-03 4 | ; 5 | ; Description: 6 | ; Call stub for calling 64-bit Linux, BSD or Mac functions from Windows 7 | ; with two vector parameters. 8 | ; 9 | ; (c) 2008 GNU General Public License www.gnu.org/copyleft/gpl.html 10 | ; ***************************************************************************** 11 | ; 12 | ; This call stub takes care of the differences between the calling conventions 13 | ; of 64-bit Windows and 64-bit Unix systems (Linux, BSD, Mac OS X) when a 14 | ; function with vector parameters compiled for a Unix system is called from 15 | ; Windows. No stub is needed in 32-bit systems. 16 | ; 17 | ; See the manual for instructions 18 | ; 19 | ; Requirements: 20 | ; The converted function must meet the following requirements: 21 | ; 22 | ; * Must not call any system functions or any library functions or 23 | ; access any data not available on the target system. 24 | ; 25 | ; * Must have exactly two parameters. 26 | ; 27 | ; * Both parameters must be of type __m128, __m128i or __m128d. 28 | ; 29 | ; * No parameter can be a pointer, reference or any other type than 30 | ; the intrinsic vector types mentioned above. 31 | ; 32 | ; * The function cannot be member of a class or structure. 33 | ; 34 | ; * The return can be void or any type, except a composite type 35 | ; requiring a return pointer. 36 | ; 37 | ; * The function should preferably have extern "C" declaration in both 38 | ; systems. If the declaration is not extern "C" then the mangled names 39 | ; must be translated manually. 40 | ; 41 | ; * The function should preferably not use the red zone. Compile the Unix 42 | ; function with option -mno-red-zone if possible. If the function uses 43 | ; the red zone then it will still work in Windows most of the time, but 44 | ; it may fail with an extremely low frequency in case the system discards 45 | ; the area above the stack when it is low on memory. 46 | ; 47 | ; If the function has more than two parameters or a mixture of vector 48 | ; and non-vector parameters then you have to make your own stub assembler 49 | ; code to account for the differences in parameter transfer methods. 50 | ; 51 | ; If the converted Unix function calls another converted Unix function then 52 | ; no stub is needed for the latter call. If the converted Unix function calls 53 | ; a Windows function then the call must go through a reverse stub created 54 | ; from w2ustub or w2ustubvec. 55 | ; 56 | ; See www.agner.org/optimize/calling_conventions.pdf for further details 57 | ; about differences in calling conventions. 58 | ; **************************************************************************** 59 | 60 | .code 61 | 62 | extern uname: near 63 | 64 | wname proc ; call from Windows goes here 65 | 66 | ; Make space for 10 xmm registers, 2 G.P. registers, 67 | ; and align stack by 16 68 | sub rsp, 184; 10*16 + 2*8 + 8 69 | 70 | ; Register rsi, rdi and xmm6 - xmm15 have callee-save status 71 | ; in Windows, but not in Unix: 72 | mov [rsp], rsi 73 | mov [rsp+8], rdi 74 | movaps [rsp+10h], xmm6 75 | movaps [rsp+20h], xmm7 76 | movaps [rsp+30h], xmm8 77 | movaps [rsp+40h], xmm9 78 | movaps [rsp+50h], xmm10 79 | movaps [rsp+60h], xmm11 80 | movaps [rsp+70h], xmm12 81 | movaps [rsp+80h], xmm13 82 | movaps [rsp+90h], xmm14 83 | movaps [rsp+0A0h],xmm15 84 | 85 | ; Windows parameters ([rcx],[rdx],[r8],[r9]) -> Unix parameters (xmm0, xmm1, xmm2, xmm3) 86 | movaps xmm0, [rcx] ; Parameter 1 87 | movaps xmm1, [rdx] ; Parameter 2 88 | ;movaps xmm2, [r8] ; Parameter 3 89 | ;movaps xmm2, [r9] ; Parameter 4 90 | 91 | call uname ; Call to Unix function here 92 | 93 | ; Restore saved registers 94 | mov rsi, [rsp] 95 | mov rdi, [rsp+8] 96 | movaps xmm6, [rsp+10h] 97 | movaps xmm7, [rsp+20h] 98 | movaps xmm8, [rsp+30h] 99 | movaps xmm9, [rsp+40h] 100 | movaps xmm10, [rsp+50h] 101 | movaps xmm11, [rsp+60h] 102 | movaps xmm12, [rsp+70h] 103 | movaps xmm13, [rsp+80h] 104 | movaps xmm14, [rsp+90h] 105 | movaps xmm15, [rsp+0A0h] 106 | 107 | ; restore stack pointer 108 | add rsp, 184 109 | ret 110 | 111 | wname endp 112 | 113 | end 114 | -------------------------------------------------------------------------------- /src/maindef.h: -------------------------------------------------------------------------------- 1 | /**************************** maindef.h ********************************** 2 | * Author: Agner Fog 3 | * Date created: 2006-08-26 4 | * Last modified: 2012-08-23 5 | * Project: objconv 6 | * Module: maindef.h 7 | * Description: 8 | * Header file for type definitions and other main definitions. 9 | * 10 | * Copyright 2006-2012 GNU General Public License http://www.gnu.org/licenses 11 | *****************************************************************************/ 12 | #ifndef MAINDEF_H 13 | #define MAINDEF_H 14 | 15 | // Program version 16 | #define OBJCONV_VERSION 2.16 17 | 18 | 19 | // Integer type definitions with platform-independent sizes: 20 | #include 21 | #if defined(_I64_MAX) 22 | // Microsoft compilers use __int64 etc 23 | typedef char int8; // 8 bit signed integer 24 | typedef unsigned char uint8; // 8 bit unsigned integer 25 | typedef short int int16; // 16 bit signed integer 26 | typedef unsigned short int uint16; // 16 bit unsigned integer 27 | typedef int int32; // 32 bit signed integer 28 | typedef unsigned int uint32; // 32 bit unsigned integer 29 | typedef __int64 int64; // 64 bit signed integer 30 | typedef unsigned __int64 uint64; // 64 bit unsigned integer 31 | 32 | #elif defined(INT_MAX) && defined(LLONG_MAX) && INT_MAX==2147483647L && LLONG_MAX==9223372036854775807LL 33 | // Compiler has int = 32 bit and long long = 64 bit 34 | typedef char int8; // 8 bit signed integer 35 | typedef unsigned char uint8; // 8 bit unsigned integer 36 | typedef short int int16; // 16 bit signed integer 37 | typedef unsigned short int uint16; // 16 bit unsigned integer 38 | typedef int int32; // 32 bit signed integer 39 | typedef unsigned int uint32; // 32 bit unsigned integer 40 | typedef long long int64; // 64 bit signed integer 41 | typedef unsigned long long uint64; // 64 bit unsigned integer 42 | 43 | #else 44 | // Compilers supporting C99 or C++0x or C++1x have inttypes.h defining these integer types 45 | // This is the preferred solution: 46 | #include 47 | //typedef int8_t int8; // Gnu compiler can't convert int8_t to char 48 | typedef char int8; // 8 bit signed integer 49 | typedef uint8_t uint8; // 8 bit unsigned integer 50 | typedef int16_t int16; // 16 bit signed integer 51 | typedef uint16_t uint16; // 16 bit unsigned integer 52 | typedef int32_t int32; // 32 bit signed integer 53 | typedef uint32_t uint32; // 32 bit unsigned integer 54 | typedef int64_t int64; // 64 bit signed integer 55 | typedef uint64_t uint64; // 64 bit unsigned integer 56 | #endif 57 | 58 | 59 | // Get high part of a 64-bit integer 60 | static inline uint32 HighDWord (uint64 x) { 61 | return (uint32)(x >> 32); 62 | } 63 | 64 | // Check if compiling for big-endian machine 65 | // (__BIG_ENDIAN__ may not be defined even on big endian systems, so this check is not 66 | // sufficient. A further check is done in CheckEndianness() in main.cpp) 67 | #if defined(__BIG_ENDIAN__) && (__BIG_ENDIAN__ != 4321) 68 | #error This machine has big-endian memory organization. Objconv program will not work 69 | #endif 70 | 71 | // Max file name length 72 | #define MAXFILENAMELENGTH 256 73 | 74 | 75 | // File types 76 | #define FILETYPE_COFF 1 // Windows COFF/PE file 77 | #define FILETYPE_OMF 2 // Windows OMF file 78 | #define FILETYPE_ELF 3 // Linux or BSD ELF file 79 | #define FILETYPE_MACHO_LE 4 // Mach-O file, little endian 80 | #define FILETYPE_MACHO_BE 5 // Mach-O file, big endian 81 | #define FILETYPE_DOS 6 // DOS file 82 | #define FILETYPE_WIN3X 7 // Windows 3.x file 83 | #define IMPORT_LIBRARY_MEMBER 0x10 // Member of import library, Windows 84 | #define FILETYPE_MAC_UNIVBIN 0x11 // Macintosh universal binary 85 | #define FILETYPE_MS_WPO 0x20 // Object file for whole program optimization, MS 86 | #define FILETYPE_INTEL_WPO 0x21 // Object file for whole program optimization, Intel 87 | #define FILETYPE_WIN_UNKNOWN 0x29 // Unknown subtype, Windows 88 | #define FILETYPE_ASM 0x100 // Disassembly output 89 | #define FILETYPE_LIBRARY 0x1000 // UNIX-style library/archive 90 | #define FILETYPE_OMFLIBRARY 0x2000 // OMF-style library 91 | 92 | 93 | // Define constants for symbol scope 94 | #define S_LOCAL 0 // Local symbol. Accessed only internally 95 | #define S_PUBLIC 1 // Public symbol. Visible from other modules 96 | #define S_EXTERNAL 2 // External symbol. Defined in another module 97 | 98 | 99 | // Macro to calculate the size of an array 100 | #define TableSize(x) (sizeof(x)/sizeof(x[0])) 101 | 102 | 103 | // Structures and functions used for lookup tables: 104 | 105 | // Structure of integers and char *, used for tables of text strings 106 | struct SIntTxt { 107 | int a; 108 | const char * b; 109 | }; 110 | 111 | // Translate integer value to text string by looking up in table of SIntTxt. 112 | // Parameters: p = table, n = length of table, x = value to find in table 113 | static inline char const * LookupText(SIntTxt const * p, int n, int x) { 114 | for (int i=0; ia == x) return p->b; 116 | } 117 | // Not found 118 | static char utext[32]; 119 | sprintf(utext, "unknown(0x%X)", x); 120 | return utext; 121 | } 122 | 123 | // Macro to get length of text list and call LookupText 124 | #define Lookup(list,x) LookupText(list, sizeof(list)/sizeof(list[0]), x) 125 | 126 | 127 | // Function to convert powers of 2 to index 128 | int FloorLog2(uint32 x); 129 | 130 | // Convert 32 bit time stamp to string 131 | const char * timestring(uint32 t); 132 | 133 | #endif // #ifndef MAINDEF_H 134 | -------------------------------------------------------------------------------- /src/library.h: -------------------------------------------------------------------------------- 1 | /**************************** library.h ******************************** 2 | * Author: Agner Fog 3 | * Date created: 2006-07-15 4 | * Last modified: 2007-02-14 5 | * Project: objconv 6 | * Module: library.h 7 | * Description: 8 | * Header file defining classes for reading and writing UNIX and OMF style 9 | * libraries. 10 | * 11 | * Copyright 2007-2008 GNU General Public License http://www.gnu.org/licenses 12 | *****************************************************************************/ 13 | 14 | #ifndef LIBRARY_H 15 | #define LIBRARY_H 16 | 17 | 18 | // Make big-endian numbers for library 19 | uint32 EndianChange(uint32); // Convert little-endian to big-endian number, or vice versa 20 | 21 | 22 | // Define UNIX library member header 23 | struct SUNIXLibraryHeader { 24 | char Name[16]; // Member name 25 | char Date[12]; // Member date, seconds, decimal ASCII 26 | char UserID[6]; // Member User ID, decimal ASCII 27 | char GroupID[6]; // Member Group ID, decimal ASCII 28 | char FileMode[8]; // Member file mode, octal 29 | char FileSize[10]; // Member file size, decimal ASCII 30 | char HeaderEnd[2]; // "`\n" 31 | }; 32 | 33 | 34 | // Class for extracting members from library or building a library 35 | class CLibrary : public CFileBuffer { 36 | public: 37 | CLibrary(); // Constructor 38 | void Go(); // Do whatever the command line says 39 | void Dump(); // Print contents of library 40 | static char *TruncateMemberName(char const*); // Remove path and truncate object file name to 15 characters 41 | const char * GetModuleName(uint32 Index); // Get name of module from index or page index 42 | protected: 43 | // Properties for UNIX input libraries only 44 | uint32 LongNames; // Offset to long names member 45 | uint32 LongNamesSize; // Size of long names member 46 | uint32 AlignBy; // Member alignment 47 | 48 | // Properties for OMF input libraries only 49 | uint32 PageSize; // Alignment of members 50 | uint32 DictionaryOffset; // Offset to hash table 51 | uint32 DictionarySize; // Dictionary size, in 512 bytes blocks 52 | 53 | // Methods and properties for reading library: 54 | void DumpUNIX(); // Print contents of UNIX style library 55 | void DumpOMF(); // Print contents of OMF style library 56 | void CheckOMFHash(CMemoryBuffer &stringbuf, CSList &index);// Check if OMF library hash table has correct entries for all symbol names 57 | void StartExtracting(); // Initialize before ExtractMember() 58 | const char * ExtractMember(CFileBuffer*); // Extract next library member from input library 59 | const char * ExtractMemberUNIX(CFileBuffer*); // Extract member of UNIX style library 60 | const char * ExtractMemberOMF(CFileBuffer*); // Extract member of OMF style library 61 | uint32 NextHeader(uint32 Offset); // Loop through library headers 62 | CConverter MemberBuffer; // Buffer containing single library member 63 | uint32 CurrentOffset; // Offset to current member 64 | uint32 CurrentNumber; // Number of current member 65 | int MemberFileType; // File type of members 66 | // Methods and properties for modifying or writing library 67 | void Rebuild(); // Make member names unique and without path. Rebuild symbol table 68 | void RebuildUNIX(); // Rebuild UNIX style library 69 | void RebuildOMF(); // Rebuild OMF style library 70 | void InsertMember(CFileBuffer*); // Add next library member to output library 71 | void InsertMemberUNIX(CFileBuffer*);// Add member to UNIX library 72 | void InsertMemberOMF(CFileBuffer*); // Add member to OMF library 73 | void MakeBinaryFile(); // Combine string index and members into binary file 74 | void MakeBinaryFileUNIX(); // Make UNIX library 75 | void MakeBinaryFileOMF(); // Make OMF library 76 | char * FixMemberNameUNIX(char const *name); // Truncate library member name to 15 characters and make unique 77 | char * FixMemberNameOMF(char const *name); // Truncate library member name to 15 characters and make unique 78 | void SortStringTable(); // Sort the string table 79 | void MakeSymbolTableUnix(); // Make symbol table for COFF, ELF or MACHO library 80 | CFileBuffer OutFile; // Buffer for building output file 81 | CSList StringEntries; // String table using SStringEntry 82 | CMemoryBuffer StringBuffer; // Buffer containing strings 83 | CMemoryBuffer DataBuffer; // Buffer containing raw members 84 | CSList Indexes; // Buffer containing indexes into DataBuffer 85 | int MemberNameExistsUNIX(char * name);// Check if DataBuffer contains a member with this name 86 | int RepressWarnings; // Repress warnings when rebuilding library 87 | }; 88 | 89 | 90 | // Definitions for OMF library hash table: 91 | 92 | #define OMFNumBuckets 37 // Number of buckets per block 93 | 94 | #define OMFBlockSize 512 // Size of each block 95 | 96 | // Structure of hash table block 97 | union SOMFHashBlock { 98 | struct { 99 | uint8 Buckets[OMFNumBuckets]; // Indicators for each bucket 100 | uint8 FreeSpace; // Pointer to free space 101 | uint8 Data[OMFBlockSize-OMFNumBuckets-1]; // Contains strings and module indices 102 | } b; 103 | uint8 Strings[OMFBlockSize]; // Start of each string = length 104 | }; 105 | 106 | 107 | // Hash table handler 108 | class COMFHashTable { 109 | public: 110 | void Init(SOMFHashBlock * blocks, uint32 NumBlocks); // Initialize 111 | void MakeHash(int8 * name); // Compute hash 112 | int FindString(uint32 & ModulePage, uint32 & Conflicts); // Search for string. Get number of occurrences, module, number of conflicting strings 113 | int InsertString(uint16 & ModulePage); // Insert string in hash table. Return 0 if success 114 | void MakeHashTable(CSList & StringEntries, CMemoryBuffer & StringBuffer, CMemoryBuffer & HashTable, CLibrary * Library); // Make hash table 115 | protected: 116 | uint8 * String; // String to search for or insert 117 | uint32 StringLength; // Length of string 118 | SOMFHashBlock * blocks; // Pointer to blocks 119 | uint32 NumBlocks; // Number of blocks 120 | uint16 StartBlock; // Start block for search 121 | uint16 StartBucket; // Start bucket for search 122 | uint16 BlockD; // Block step size in search 123 | uint16 BucketD; // Bucket step size in search 124 | }; 125 | 126 | #endif // #ifndef LIBRARY_H 127 | -------------------------------------------------------------------------------- /src/objconv.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | 27 | 30 | 33 | 36 | 39 | 42 | 57 | 60 | 63 | 66 | 77 | 80 | 83 | 86 | 89 | 92 | 95 | 98 | 99 | 107 | 110 | 113 | 116 | 119 | 122 | 138 | 141 | 144 | 147 | 159 | 162 | 165 | 168 | 171 | 174 | 177 | 180 | 181 | 182 | 183 | 184 | 185 | 190 | 193 | 194 | 197 | 198 | 201 | 202 | 205 | 206 | 209 | 210 | 213 | 214 | 217 | 218 | 221 | 222 | 225 | 226 | 229 | 230 | 233 | 234 | 237 | 238 | 241 | 242 | 245 | 246 | 249 | 250 | 253 | 254 | 257 | 258 | 261 | 262 | 265 | 266 | 269 | 270 | 273 | 274 | 277 | 278 | 281 | 282 | 285 | 286 | 289 | 290 | 293 | 294 | 297 | 300 | 304 | 305 | 308 | 312 | 313 | 314 | 315 | 320 | 323 | 324 | 327 | 328 | 331 | 332 | 335 | 336 | 339 | 340 | 343 | 344 | 347 | 348 | 351 | 352 | 355 | 356 | 359 | 360 | 363 | 364 | 367 | 368 | 369 | 374 | 375 | 376 | 377 | 378 | 379 | -------------------------------------------------------------------------------- /src/cmdline.h: -------------------------------------------------------------------------------- 1 | /**************************** cmdline.h *********************************** 2 | * Author: Agner Fog 3 | * Date created: 2006-07-25 4 | * Last modified: 2006-07-25 5 | * Project: objconv 6 | * Module: cmdline.h 7 | * Description: 8 | * Header file for command line interpreter cmdline.cpp 9 | * 10 | * Copyright 2006-2008 GNU General Public License http://www.gnu.org/licenses 11 | *****************************************************************************/ 12 | #ifndef CMDLINE_H 13 | #define CMDLINE_H 14 | 15 | /************************** Define constants ******************************/ 16 | // Max number of response files on command line 17 | #define MAX_COMMAND_FILES 10 18 | 19 | // Constants for output file type 20 | #define CMDL_OUTPUT_DUMP 0x80 // No output file, just dump contents 21 | #define CMDL_OUTPUT_ELF FILETYPE_ELF // ELF file 22 | #define CMDL_OUTPUT_PE FILETYPE_COFF // MS-COFF/PE file 23 | #define CMDL_OUTPUT_OMF FILETYPE_OMF // OMF file 24 | #define CMDL_OUTPUT_MACHO FILETYPE_MACHO_LE // Mach-O file, little endian 25 | #define CMDL_OUTPUT_MASM FILETYPE_ASM // Disassembly 26 | 27 | // Constants for subtypes 28 | #define SUBTYPE_MASM 0 // Disassembly MASM/TASM 29 | #define SUBTYPE_YASM 1 // Disassembly NASM/YASM 30 | #define SUBTYPE_GASM 2 // Disassembly GAS(Intel) 31 | 32 | // Constants for verbose or silent console output 33 | #define CMDL_VERBOSE_NO 0 // Silent. No console output if no errors or warnings 34 | #define CMDL_VERBOSE_YES 1 // Output messages about file names and types 35 | #define CMDL_VERBOSE_DIAGNOSTICS 2 // Output more messages 36 | 37 | // Constants for dump options 38 | #define DUMP_NONE 0x0000 // Dump nothing 39 | #define DUMP_FILEHDR 0x0001 // Dump file header 40 | #define DUMP_SECTHDR 0x0002 // Dump section headers 41 | #define DUMP_SYMTAB 0x0010 // Dump symbol table 42 | #define DUMP_RELTAB 0x0020 // Dump relocation table 43 | #define DUMP_STRINGTB 0x0040 // Dump string table 44 | #define DUMP_COMMENT 0x0080 // Dump comment records 45 | 46 | // Constants for stripping or converting debug information from file 47 | #define CMDL_DEBUG_DEFAULT 0 // Remove if output is different format 48 | #define CMDL_DEBUG_STRIP 1 // Remove debugging information from file 49 | #define CMDL_DEBUG_PRESERVE 2 // Leave debugging information unchanged 50 | #define CMDL_DEBUG_LINNUM 4 // Convert line number information (not supported) 51 | #define CMDL_DEBUG_SYMBOLS 8 // Convert symbol information (not supported) 52 | 53 | // Constants for stripping exception handler information from file 54 | #define CMDL_EXCEPTION_DEFAULT 0 // Remove if output is different format 55 | #define CMDL_EXCEPTION_STRIP 1 // Remove exception handler information from file 56 | #define CMDL_EXCEPTION_PRESERVE 2 // Leave exception handler information unchanged 57 | 58 | // Constants for adding/removing leading underscores from symbol names 59 | #define CMDL_UNDERSCORE_NOCHANGE 0 // Don't add or remove underscores 60 | #define CMDL_UNDERSCORE_CHANGE 1 // Change underscores to default for target 61 | #define CMDL_UNDERSCORE_REMOVE 2 // Remove underscores from symbol names 62 | #define CMDL_UNDERSCORE_ADD 3 // Add underscores to symbol names 63 | #define CMDL_KEEP_ALIAS 0x10 // Keep old name as alias 64 | 65 | // Constants for replacing leading dot with underscore or vice versa in section names 66 | #define CMDL_SECTIONDOT_NOCHANGE 0 // Don't change section names 67 | #define CMDL_SECTIONDOT_CHANGE 1 // Change leading character in section names to default for target 68 | #define CMDL_SECTIONDOT_U2DOT 2 // Change underscore to dot in section names 69 | #define CMDL_SECTIONDOT_DOT2U 3 // Change dot to underscore in unknown section names 70 | 71 | // Constants for library options 72 | #define CMDL_LIBRARY_DEFAULT 0 // No option specified 73 | #define CMDL_LIBRARY_CONVERT 1 // Convert or modify library 74 | #define CMDL_LIBRARY_ADDMEMBER 2 // Add object file to library 75 | #define CMDL_LIBRARY_EXTRACTMEM 0x100 // Extract specified object file(s) from library 76 | #define CMDL_LIBRARY_EXTRACTALL 0x110 // Extract all object files from library 77 | 78 | // Constants for file input/output options 79 | #define CMDL_FILE_INPUT 1 // Input file required 80 | #define CMDL_FILE_IN_IF_EXISTS 2 // Read input file if it exists 81 | #define CMDL_FILE_OUTPUT 0x10 // Write output file required 82 | #define CMDL_FILE_IN_OUT_SAME 0x20 // Input and output files may have the same name 83 | 84 | #define MAXSYMBOLLENGTH 1024 // Maximum length of symbols for changing underscore or dot 85 | 86 | // Constants for symbol type as input to CCommandLineInterpreter::SymbolChange() 87 | #define SYMT_OTHER 0 // File name or unknown symbol type 88 | #define SYMT_SECTION 1 // Segment or section name 89 | #define SYMT_LOCAL 2 // Local symbol (not imported or exported) 90 | #define SYMT_PUBLIC 3 // Public or weak symbol (exported) 91 | #define SYMT_EXTERNAL 4 // External symbol (imported) 92 | #define SYMT_LIBRARYMEMBER 0x1000 // Name of library member 93 | 94 | // Constants for symbol change action as defined in SSymbolChange::Action 95 | // and output from CCommandLineInterpreter::SymbolChange() 96 | #define SYMA_NOCHANGE 0 // Do nothing 97 | #define SYMA_MAKE_WEAK 1 // Make symbol weak 98 | #define SYMA_MAKE_LOCAL 2 // Make symbol local 99 | #define SYMA_CHANGE_NAME 4 // Change name of symbol 100 | #define SYMA_CHANGE_PREFIX 8 // Change beginning of symbol name 101 | #define SYMA_CHANGE_ALIAS 0x14 // Make alias and keep old name 102 | #define SYMA_ADD_MEMBER 0x1001 // Add member to library 103 | #define SYMA_DELETE_MEMBER 0x1002 // Remove member from library 104 | #define SYMA_EXTRACT_MEMBER 0x1004 // Extract member from library 105 | 106 | // Structure for specifying desired change of a specific symbol 107 | struct SSymbolChange { 108 | char * Name1; // Symbol name to look for 109 | char * Name2; // Replace with this name 110 | int Action; // Action to take on symbol 111 | int Done; // Count how many times this has been done 112 | }; 113 | 114 | // Class for interpreting command line 115 | class CCommandLineInterpreter { 116 | public: 117 | CCommandLineInterpreter(); // Default constructor 118 | ~CCommandLineInterpreter(); // Destructor 119 | void ReadCommandLine(int argc, char * argv[]); // Read and interpret command line 120 | int SymbolChange(char const * oldname, char const ** newname, int symtype); // Check if symbol has to be changed 121 | int SymbolIsInList(char const * name); // Check if symbol is in SymbolList 122 | int SymbolChangesRequested(); // Any kind of symbol change requested on command line 123 | void ReportStatistics(); // Report statistics about name changes etc. 124 | void CountDebugRemoved(); // Increment CountDebugSectionsRemoved 125 | void CountExceptionRemoved(); // Increment CountExceptionSectionsRemoved 126 | void CountSymbolsHidden(); // Increment CountUnusedSymbolsHidden 127 | SSymbolChange const * GetMemberToAdd(); // Get names of object files to add to library 128 | void CheckExtractSuccess(); // Check if library members to extract were found 129 | void CheckSymbolModifySuccess(); // Check if symbols to modify were found 130 | char * InputFile; // Input file name 131 | char * OutputFile; // Output file name 132 | int InputType; // Input file type (detected from file) 133 | int OutputType; // Output type (file type or dump) 134 | int SubType; // Subtype of output type. Assembly language dialect 135 | int MemberType; // File type of library members 136 | int DesiredWordSize; // Desired word size for output file 137 | uint32 Verbose; // How much diagnostics to print on screen 138 | uint32 DumpOptions; // Options for dumping file 139 | uint32 DebugInfo; // Strip or convert debug info 140 | uint32 ExeptionInfo; // Strip or preserve exception handler info and other incompatible info 141 | uint32 Underscore; // Add/remove underscores in symbol names 142 | uint32 SegmentDot; // Change underscore/dot in beginning of segment names 143 | uint32 LibraryOptions; // Options for manipulating library 144 | uint32 FileOptions; // Options for input and output files 145 | uint32 ImageBase; // Specified image base 146 | int ShowHelp; // Help screen printed 147 | protected: 148 | int libmode; // -lib option has been encountered 149 | void ReadCommandItem(char *); // Read one option from command line 150 | void ReadCommandFile(char *); // Read commands from file 151 | void InterpretFileName(char *); // Interpret input or output filename from command line 152 | void InterpretCommandOption(char *); // Interpret one option from command line 153 | void InterpretOutputTypeOption(char *); // Interpret output type option from command line 154 | void InterpretVerboseOption(char *); // Interpret silent/verbose option from command line 155 | void InterpretDumpOption(char *); // Interpret dump option from command line 156 | void InterpretDebugInfoOption(char *); // Interpret debug info option from command line 157 | void InterpretExceptionInfoOption(char*); // Interpret exception handler info option from command line 158 | void InterpretErrorOption(char *); // Interpret error option from command line 159 | void InterpretSymbolNameChangeOption(char *); // Interpret various options for changing symbol names 160 | void InterpretLibraryOption(char *); // Interpret options for manipulating library/archive files 161 | void InterpretImagebaseOption(char *); // Interpret image base option 162 | void AddObjectToLibrary(char * filename, char * membername); // Add object file to library 163 | void Help(); // Print help message 164 | CArrayBuf ResponseFiles; // Array of up to 10 response file buffers 165 | int NumBuffers; // Number of response file buffers 166 | int SymbolChangeEntries; // Number of entries in SymbolList, except library entries 167 | CMemoryBuffer SymbolList; // List of symbol names to change. Contains entries of type SSymbolChange 168 | CMemoryBuffer MemberNames; // Buffer containing truncated member names 169 | uint32 MemberNamesAllocated; // Size of buffer in MemberNames 170 | uint32 CurrentSymbol; // Pointer into SymbolList 171 | // Statistics counters 172 | int CountUnderscoreConversions; // Count number of times symbol leading underscores are changed 173 | int CountSectionDotConversions; // Count number of times leading character is changed on section names 174 | int CountSymbolNameChanges; // Count number of times symbol names are changed at specific command 175 | int CountSymbolNameAliases; // Count number of times symbol names are aliased at specific command or underscore command 176 | int CountSymbolsWeakened; // Count number of times symbol names are made weak at specific command 177 | int CountSymbolsMadeLocal; // Count number of times symbol names are made local at specific command 178 | int CountUnusedSymbolsHidden; // Count number of times unused symbols are hidden 179 | int CountDebugSectionsRemoved; // Count number of debug sections removed 180 | int CountExceptionSectionsRemoved; // Count number of exception handler sections removed 181 | }; 182 | 183 | extern CCommandLineInterpreter cmd; // Command line interpreter 184 | 185 | #endif // #ifndef CMDLINE_H 186 | -------------------------------------------------------------------------------- /src/cof2cof.cpp: -------------------------------------------------------------------------------- 1 | /**************************** cof2cof.cpp ********************************* 2 | * Author: Agner Fog 3 | * Date created: 2006-07-28 4 | * Last modified: 2006-07-28 5 | * Project: objconv 6 | * Module: cof2cof.cpp 7 | * Description: 8 | * Module for changing symbol names in PE/COFF file 9 | * 10 | * Copyright 2006-2008 GNU General Public License http://www.gnu.org/licenses 11 | *****************************************************************************/ 12 | #include "stdafx.h" 13 | 14 | 15 | CCOF2COF::CCOF2COF () { 16 | // Constructor 17 | } 18 | 19 | void CCOF2COF::Convert() { 20 | // Do the conversion 21 | 22 | // Call the subfunctions 23 | MakeSymbolTable(); // Symbol table and string tables 24 | MakeBinaryFile(); // Putting sections together 25 | *this << ToFile; // Take over new file buffer 26 | } 27 | 28 | 29 | void CCOF2COF::MakeSymbolTable() { 30 | // Convert subfunction: Make symbol table and string tables 31 | int isym; // current symbol table entry 32 | int numaux; // Number of auxiliary entries in source record 33 | int symboltype = 0; // Symbol type 34 | int action = 0; // Symbol change action 35 | int isec; // Section number 36 | 37 | const char * name1; // Old name of symbol 38 | const char * name2; // Changed name of symbol 39 | const char * name3; // New name to store 40 | 41 | // Pointer to old symbol table 42 | union { 43 | SCOFF_SymTableEntry * p; // Symtab entry pointer 44 | int8 * b; // Used for increment 45 | } OldSymtab; 46 | 47 | // Initialize new string table. Make space for size 48 | NewStringTable.Push(0, 4); 49 | 50 | // Loop through source symbol table 51 | OldSymtab.p = SymbolTable; // Pointer to source symbol table 52 | for (isym = 0; isym < NumberOfSymbols; isym += numaux+1, OldSymtab.b += SIZE_SCOFF_SymTableEntry*(numaux+1)) { 53 | 54 | // Number of auxiliary records belonging to same symbol 55 | numaux = OldSymtab.p->s.NumAuxSymbols; if (numaux < 0) numaux = 0; 56 | 57 | // Get first aux record if numaux > 0 58 | SCOFF_SymTableEntry * sa = (SCOFF_SymTableEntry *)(OldSymtab.b + SIZE_SCOFF_SymTableEntry); 59 | 60 | // Check symbol type 61 | if (numaux && OldSymtab.p->s.StorageClass == COFF_CLASS_STATIC) { 62 | // This is a section definition record 63 | // aux record contains length and number of relocations. Ignore aux record 64 | symboltype = SYMT_SECTION; 65 | name1 = GetSymbolName(OldSymtab.p->s.Name); 66 | } 67 | else if (OldSymtab.p->s.StorageClass == COFF_CLASS_FILE) { 68 | // This is a filename record 69 | symboltype = SYMT_OTHER; 70 | name1 = GetShortFileName(OldSymtab.p); 71 | // or long file name ?! 72 | } 73 | else if (OldSymtab.p->s.Type == 0 && OldSymtab.p->s.StorageClass == COFF_CLASS_FUNCTION) { 74 | // This is a .bf, .lf, or .ef record following a function record 75 | // Contains line number information etc. Ignore this record 76 | name1 = 0; 77 | } 78 | else { 79 | // This is a symbol record 80 | // Symbol name 81 | name1 = GetSymbolName(OldSymtab.p->s.Name); 82 | if (OldSymtab.p->s.StorageClass == COFF_CLASS_EXTERNAL) { 83 | // This is a public or external symbol 84 | if (OldSymtab.p->s.SectionNumber <= 0) { 85 | // This is an external symbol 86 | symboltype = SYMT_EXTERNAL; 87 | } 88 | else { 89 | // This is a public symbol 90 | symboltype = SYMT_PUBLIC; 91 | } 92 | } 93 | else { 94 | // This is a local symbol 95 | symboltype = SYMT_LOCAL; 96 | } 97 | } 98 | name3 = name1; 99 | // Check if any change required for this symbol 100 | action = cmd.SymbolChange(name1, &name2, symboltype); 101 | 102 | switch (action) { 103 | case SYMA_NOCHANGE: 104 | // No change 105 | break; 106 | 107 | case SYMA_MAKE_WEAK: 108 | // Make symbol weak 109 | if (cmd.OutputType == FILETYPE_COFF) { 110 | // PE/COFF format does not support weak publics. Use this only when converting to ELF 111 | err.submit(2200); 112 | } 113 | // Make weak when converting to ELF 114 | OldSymtab.p->s.StorageClass = COFF_CLASS_WEAK_EXTERNAL; 115 | break; 116 | 117 | case SYMA_MAKE_LOCAL: 118 | // Make public symbol local, make external symbol ignored 119 | OldSymtab.p->s.StorageClass = COFF_CLASS_STATIC; 120 | break; 121 | 122 | case SYMA_CHANGE_NAME: 123 | // Change name of symbol 124 | if (OldSymtab.p->s.StorageClass == COFF_CLASS_FILE) { 125 | // File name is stored in aux records, not in symbol table 126 | if ((uint32)strlen(name2) > (uint32)numaux * SIZE_SCOFF_SymTableEntry) { 127 | // Name too long. I don't want to add more aux records 128 | err.submit(2201, name2); 129 | } 130 | else { 131 | // Insert new file name in aux records 132 | memset(sa, 0, numaux * SIZE_SCOFF_SymTableEntry); 133 | memcpy(sa, name2, strlen(name2)); 134 | } 135 | } 136 | else { 137 | // Symbol name stored in normal way 138 | name3 = name2; 139 | } 140 | break; 141 | 142 | case SYMA_CHANGE_ALIAS: { 143 | // Make alias and keep old name 144 | SCOFF_SymTableEntry AliasEntry = *OldSymtab.p; 145 | AliasEntry.s.Type = 0; // Make alias a label, not a function 146 | AliasEntry.s.NumAuxSymbols = 0; // No auxiliary .bf and .ef records 147 | // Put new name into AliasEntry 148 | memset(AliasEntry.s.Name, 0, 8); 149 | if (strlen(name2) > 8) { 150 | // Long name. use string table 151 | // Store string table offset 152 | ((uint32 *)(AliasEntry.s.Name))[1] = NewStringTable.GetDataSize(); 153 | // Put name into new string table 154 | NewStringTable.PushString(name2); 155 | } 156 | else { 157 | // Short name. Store in record 158 | memcpy(AliasEntry.s.Name, name2, strlen(name2)); 159 | } 160 | // Add new entry to extra symbol table 161 | NewSymbolTable.Push(&AliasEntry, SIZE_SCOFF_SymTableEntry); 162 | break;} 163 | 164 | default: 165 | err.submit(9000); // unknown error 166 | } 167 | 168 | if (name3 && OldSymtab.p->s.StorageClass != COFF_CLASS_FILE) { 169 | // Store old or new name 170 | if (strlen(name3) > 8) { 171 | // Name is long. use string table 172 | // Type-case Name field to string table entry 173 | uint32 * LongNameStorage = (uint32 *)(OldSymtab.p->s.Name); 174 | // Start with 0 to indicate long name 175 | LongNameStorage[0] = 0; 176 | // Index into new string table 177 | LongNameStorage[1] = NewStringTable.GetDataSize(); 178 | // Put name into new string table 179 | NewStringTable.PushString(name3); 180 | } 181 | else { 182 | if (name3 != name1) { 183 | // Store new name in Name field 184 | memset(OldSymtab.p->s.Name, 0, 8); 185 | memcpy(OldSymtab.p->s.Name, name3, strlen(name3)); 186 | } 187 | } 188 | } 189 | } // End symbol table loop 190 | 191 | // Loop through section headers to search for section names 192 | uint32 SectionOffset = sizeof(SCOFF_FileHeader) + FileHeader->SizeOfOptionalHeader; 193 | for (isec = 0; isec < NSections; isec++) { 194 | SCOFF_SectionHeader * pSectHeader; 195 | pSectHeader = &Get(SectionOffset); 196 | SectionOffset += sizeof(SCOFF_SectionHeader); 197 | 198 | // Get section name 199 | name1 = GetSectionName(pSectHeader->Name); 200 | 201 | // Check if change required 202 | action = cmd.SymbolChange(name1, &name2, SYMT_SECTION); 203 | if (action == SYMA_CHANGE_NAME) name1 = name2; 204 | 205 | // Store name (changed or unchanged) 206 | memset(pSectHeader->Name, 0, 8); 207 | if (strlen(name1) <= 8) { 208 | // Short name. Store in section header 209 | memcpy(pSectHeader->Name, name1, strlen(name1)); 210 | } 211 | else { 212 | // Long name. Store in string table 213 | sprintf(pSectHeader->Name, "/%i", NewStringTable.GetDataSize()); 214 | //pSectHeader->Name[0] = '/'; 215 | //itoa(NewStringTable.GetDataSize(), pSectHeader->Name+1, 10); 216 | NewStringTable.PushString(name1); 217 | } 218 | } 219 | } 220 | 221 | 222 | void CCOF2COF::MakeBinaryFile() { 223 | // Convert subfunction: Combine everything into the new binary file 224 | int i; 225 | 226 | // New file header = copy of old file header 227 | SCOFF_FileHeader NewFileHeader = *FileHeader; 228 | 229 | ToFile.SetFileType(FILETYPE_COFF); // Set type of output file 230 | ToFile.WordSize = WordSize; 231 | ToFile.FileName = FileName; 232 | 233 | // Copy file header, section headers and sections to new file 234 | ToFile.Push(Buf(), NewFileHeader.PSymbolTable); 235 | 236 | // Copy symbol table 237 | ToFile.Push(SymbolTable, NumberOfSymbols * SIZE_SCOFF_SymTableEntry); 238 | 239 | // Additions to symbol table 240 | int NumAddedSymbols = NewSymbolTable.GetNumEntries(); 241 | if (NumAddedSymbols) { 242 | // Append to symbols table 243 | ToFile.Push(NewSymbolTable.Buf(), NumAddedSymbols * SIZE_SCOFF_SymTableEntry); 244 | // Update NumberOfSymbols in file header 245 | NewFileHeader.NumberOfSymbols += NumAddedSymbols; 246 | } 247 | 248 | // Insert new string table 249 | uint32 NewStringTableSize = NewStringTable.GetDataSize(); 250 | // First 4 bytes = size 251 | ToFile.Push(&NewStringTableSize, sizeof(uint32)); 252 | // Then the string table itself, except the first 4 bytes 253 | if (NewStringTableSize > 4) 254 | ToFile.Push(NewStringTable.Buf() + 4, NewStringTableSize - 4); 255 | 256 | // Find end of old and new string tables 257 | uint32 EndOfOldStringTable = FileHeader->PSymbolTable 258 | + NumberOfSymbols * SIZE_SCOFF_SymTableEntry + StringTableSize; 259 | 260 | uint32 EndOfNewStringTable = FileHeader->PSymbolTable 261 | + (NumberOfSymbols + NumAddedSymbols) * SIZE_SCOFF_SymTableEntry + NewStringTableSize; 262 | 263 | // Check if there is anything after the string table 264 | if (GetDataSize() > EndOfOldStringTable) { 265 | // Old file has something after the string table 266 | 267 | if (EndOfNewStringTable < EndOfOldStringTable) { 268 | // New symboltable + string table smaller than old 269 | // Fill the space with zeroes so that the data that come after the string table 270 | // will have the same address as before 271 | ToFile.Push(0, EndOfOldStringTable - EndOfNewStringTable); 272 | EndOfNewStringTable = EndOfOldStringTable; 273 | } 274 | 275 | // Copy the data that come after the string table 276 | ToFile.Push(Buf() + EndOfOldStringTable, GetDataSize() - EndOfOldStringTable); 277 | 278 | if (EndOfNewStringTable > EndOfOldStringTable) { 279 | // New symboltable + string table bigger than old 280 | // Find all references to the data that come after the string table and fix them 281 | // Search all section headers 282 | uint32 SectionOffset = sizeof(SCOFF_FileHeader) + NewFileHeader.SizeOfOptionalHeader; 283 | for (i = 0; i < NSections; i++) { 284 | SCOFF_SectionHeader * pSectHeader; 285 | pSectHeader = &Get(SectionOffset); 286 | SectionOffset += sizeof(SCOFF_SectionHeader); 287 | if (pSectHeader->PRawData >= EndOfOldStringTable && pSectHeader->PRawData <= GetDataSize()) { 288 | pSectHeader->PRawData += EndOfNewStringTable - EndOfOldStringTable; 289 | } 290 | if (pSectHeader->PRelocations >= EndOfOldStringTable && pSectHeader->PRawData <= GetDataSize()) { 291 | pSectHeader->PRelocations += EndOfNewStringTable - EndOfOldStringTable; 292 | } if (pSectHeader->PLineNumbers >= EndOfOldStringTable && pSectHeader->PRawData <= GetDataSize()) { 293 | pSectHeader->PLineNumbers += EndOfNewStringTable - EndOfOldStringTable; 294 | } 295 | } 296 | } 297 | } 298 | // Update file header 299 | memcpy(ToFile.Buf(), &NewFileHeader, sizeof(NewFileHeader)); 300 | 301 | // Note: The checksum in the optional header may need to be updated. 302 | // This is relevant for DLL's only. The checksum algorithm is undisclosed and 303 | // must be calculated with IMAGHELP.DLL. You may add a calculation of the checksum 304 | // here if you want the program to be able to change names in a Windows DLL, 305 | // but the program will then only be able to compile under Windows. 306 | } 307 | -------------------------------------------------------------------------------- /src/omf.h: -------------------------------------------------------------------------------- 1 | /***************************** omf.h ************************************* 2 | * Author: Agner Fog 3 | * Date created: 2007-01-29 4 | * Last modified: 2007-01-29 5 | * Project: objconv 6 | * Module: omf.h 7 | * Description: 8 | * Header file for definition of data structures and constants in OMF object 9 | * file format. Also defines class COMFFileBuilder. 10 | * 11 | * Copyright 2006-2008 GNU General Public License http://www.gnu.org/licenses 12 | ****************************************************************************** 13 | * 14 | * An OMF file consists of a chain of records which all have the same basic 15 | * structure: 16 | * 1. One byte describing the type of record 17 | * 2. A 16-bit word indicating the length of the rest of the record 18 | * 3. Data of variable types and sizes (max 1024 bytes) 19 | * 4. One byte for checksum. Some systems just set this byte to 0 20 | * 21 | * The OMF format is designed for compactness. All integers of type "index" 22 | * are represented by one byte if no bigger than 127, or by two bytes if 23 | * 128 or more. The most significant bit of the first byte indicates whether 24 | * there are one or two bytes. Integers indicating a segment offset are 16 25 | * bits if the type byte is even, or 32 bits if the type byte is odd. 26 | * Some fields can be left out if they are zero or repeated. The precense 27 | * or absense of a particular field may depend on certain bits in the preceding 28 | * fields. The records cannot be defined as C++ structures because a field 29 | * with variable size or a field that can be absent makes the position of the 30 | * subsequent fields variable. 31 | * 32 | * For these reasons, you will not find any structures defining OMF records 33 | * in this header file. Only the bitfields that are used are defined here. 34 | * Instead, I have defined the member functions of SOMFRecordPointer for 35 | * reading fields of various types occurring in OMF records, and the member 36 | * functions of COMFFileBuilder for writing these fields. The structure of 37 | * an OMF record is simply defined by calling these functions in the right 38 | * order. 39 | * 40 | * The size of the data field is limited to 1024 bytes because records of type 41 | * FIXUPP have only 10 bits for indexing into the data field of a preceding 42 | * record of type LEDATA or LIDATA. Most tools (but not all!) limit the size 43 | * of all types of records to 1024 bytes of data, although this limitation 44 | * is technically necessary only for LEDATA and LIDATA records. A segment 45 | * bigger than one kilobyte must be split into several LEDATA records. Each 46 | * LEDATA record is followed by a FIXUPP record if it has relocations. 47 | * 48 | * Symbol names and other text strings are stored with one byte indicating the 49 | * length of the string followed by an ASCII string without terminating zero. 50 | * Consequently, the length of all symbol names is limited to 255 characters. 51 | * 52 | *****************************************************************************/ 53 | 54 | #ifndef OMF_H 55 | #define OMF_H 56 | 57 | //********************** Record types ********************** 58 | 59 | #define OMF_THEADR 0x80 // Translator Header Record 60 | #define OMF_LHEADR 0x82 // Library Module Header Record 61 | #define OMF_COMENT 0x88 // Comment Record (Including all comment class extensions) 62 | #define OMF_MODEND 0x8A // (0x8B) Module End Record 63 | #define OMF_EXTDEF 0x8C // External Names Definition Record 64 | #define OMF_PUBDEF 0x90 // (0x91) Public Names Definition Record 65 | #define OMF_LINNUM 0x94 // (0x95) Line Numbers Record 66 | #define OMF_LNAMES 0x96 // List of Names Record 67 | #define OMF_SEGDEF 0x98 // (0x99) Segment Definition Record 68 | #define OMF_GRPDEF 0x9A // Group Definition Record 69 | #define OMF_FIXUPP 0x9C // (0x9D) Fixup Record 70 | #define OMF_LEDATA 0xA0 // (0xA1) Logical Enumerated Data Record 71 | #define OMF_LIDATA 0xA2 // (0xA3) Logical Iterated Data Record 72 | #define OMF_COMDEF 0xB0 // Communal Names Definition Record 73 | #define OMF_BAKPAT 0xB2 // (0xB3) Backpatch Record 74 | #define OMF_LEXTDEF 0xB4 // Local External Names Definition Record 75 | #define OMF_LPUBDEF 0xB6 // (0xB7) Local Public Names Definition Record 76 | #define OMF_LCOMDEF 0xB8 // Local Communal Names Definition Record 77 | #define OMF_CEXTDEF 0xBC // COMDAT External Names Definition Record 78 | #define OMF_COMDAT 0xC2 // (0xC3) Initialized Communal Data Record 79 | #define OMF_LINSYM 0xC4 // (0xC5) Symbol Line Numbers Record 80 | #define OMF_ALIAS 0xC6 // Alias Definition Record 81 | #define OMF_NBKPAT 0xC8 // (0xC9) Named Backpatch Record 82 | #define OMF_LLNAMES 0xCA // Local Logical Names Definition Record 83 | #define OMF_VERNUM 0xCC // OMF Version Number Record 84 | #define OMF_VENDEXT 0xCE // Vendor-specific OMF Extension Record 85 | #define OMF_LIBHEAD 0xF0 // Library Header Record 86 | #define OMF_LIBEND 0xF1 // Library End Record 87 | #define OMF_LIBEXT 0xF2 // Library extended dictionary 88 | 89 | 90 | /********************** Relocation types **********************/ 91 | 92 | #define OMF_Fixup_8bit 0 // 8 bit or low byte of 16 bits 93 | #define OMF_Fixup_16bit 1 // 16 bit offset 94 | #define OMF_Fixup_Segment 2 // 16 bit segment selector 95 | #define OMF_Fixup_Far 3 // 16 bit offset + 16 big segment 96 | #define OMF_Fixup_Hi8bit 4 // High 8 bits of 16 bit offset 97 | #define OMF_Fixup_16bitLoader 5 // 16 bit, loader resolved 98 | #define OMF_Fixup_Pharlab48 6 // 32 bit offset + 16 bit segment, Pharlab only 99 | #define OMF_Fixup_32bit 9 // 32 bit offset 100 | #define OMF_Fixup_Farword 11 // 32 bit offset + 16 bit segment 101 | #define OMF_Fixup_32bitLoader 13 // 32 bit, loader resolved 102 | 103 | // Define fixed indexes in LNAMES for default group and class names 104 | #define OMF_LNAME_FLAT 1 // Default group name 105 | #define OMF_LNAME_CODE 2 // Default class for code 106 | #define OMF_LNAME_DATA 3 // Default class for data 107 | #define OMF_LNAME_BSS 4 // Default class for uninitialized data 108 | #define OMF_LNAME_CONST 5 // Default class for constant data 109 | #define OMF_LNAME_LAST 5 // Last default name. Nondefault names start at OMF_LNAME_LAST + 1 110 | // Class name STACK not used 111 | 112 | 113 | // Define bitfield structures used in OMF records 114 | 115 | union OMF_SAttrib { // Structure of attributes in SEGDEF record 116 | uint8 b; // Byte 117 | struct { 118 | uint8 P:1, // 0: 16 bit, 1: 32 bit 119 | B:1, // Big 120 | C:3, // Combination (private, public, stack, common) 121 | A:3; // Alignment 122 | } u; 123 | }; 124 | 125 | union OMF_SLocat { // Structure of first two bytes of FIXUP subrecord swapped = Locat field 126 | uint8 bytes[2]; // First two bytes swapped 127 | struct { 128 | uint16 Offset:10, // Offset into LEDATA (or LIDATA) 129 | Location:4, // Relocation method 130 | M:1, // 0 = self-relative, 1 = direct 131 | one:1; // 1 = FIXUP subrecord, 0 = THREAD subrecord 132 | } s; 133 | }; 134 | 135 | union OMF_SFixData { // Structure of FixData field in FIXUP subrecord of FIXUPP record 136 | uint8 b; // Byte 137 | struct { 138 | uint8 Target:2, // Target method (T=0) or target thread number (T=1) 139 | P:1, // 0 = target displacement field present, 1 = displacement is zero 140 | T:1, // 0 = target field present, 1 = target defined by thread 141 | Frame:3, // Frame method (F=0) or frame thread (F=1) 142 | F:1; // 0 = target frame field present, 1 = frame defined by thread 143 | } s; 144 | }; 145 | 146 | union OMF_STrdDat { // Structure of Thread Data field in THREAD subrecord of FIXUPP record 147 | uint8 b; // Byte 148 | struct { 149 | uint8 Thread:2, // Thread number 150 | Method:3, // Method (T0 - T3, F0 - F6) 151 | Unused:1, // 0 152 | D:1, // 0 = Target thread, 1 = Frame thread 153 | Zero:1; // 1 = FIXUP subrecord, 0 = THREAD subrecord 154 | } s; 155 | }; 156 | 157 | 158 | // Structure of OMF record pointer 159 | struct SOMFRecordPointer { 160 | public: 161 | uint8 Type; // Record type 162 | uint8 Type2; // Record type, made even 163 | uint16 Unused; // Align 164 | uint32 FileOffset; // Position in file 165 | uint32 FileEnd; // End of file = file size 166 | uint32 Index; // Offset to current byte while parsing from start of record 167 | uint32 End; // Offset to checksum byte from start of record 168 | int8 * buffer; // Pointer to file buffer 169 | uint8 GetByte(); // Read next byte from buffer 170 | uint16 GetWord(); // Read next 16 bit word from buffer 171 | uint32 GetDword(); // Read next 32 bit dword from buffer 172 | uint32 GetIndex(); // Read byte or word, depending on sign of first byte 173 | uint32 GetNumeric(); // Read word or dword, depending on record type even or odd 174 | uint32 GetLength(); // Read 1, 2, 3 or 4 bytes, depending on value of first byte 175 | char * GetString(); // Read string and return as ASCIIZ string 176 | void Start(int8 * Buffer, uint32 FileOffset, uint32 FileEnd); // Start scanning through records 177 | uint8 GetNext(uint32 align = 0);// Get next record 178 | uint32 InterpretLIDATABlock(); // Interpret Data block in LIDATA record recursively 179 | uint32 UnpackLIDATABlock(int8 * destination, uint32 MaxSize); // Unpack Data block in LIDATA record recursively and store data at destination 180 | }; 181 | 182 | 183 | // Class for building OMF files 184 | class COMFFileBuilder : public CFileBuffer { 185 | public: 186 | COMFFileBuilder(); // Constructor 187 | void StartRecord(uint8 type); // Start building new record 188 | void EndRecord(); // Finish building current record 189 | void PutByte(uint8); // Put byte into buffer 190 | void PutWord(uint16); // Put 16 bit word into buffer 191 | void PutDword(uint32); // Put 32 bit dword into buffer 192 | void PutIndex(uint32); // Put byte or word into buffer (word if > 127) 193 | void PutNumeric(uint32); // Put word or dword into buffer, depending on type being even or odd 194 | void PutString(const char *); // Put ASCII string into buffer, preceded by size 195 | void PutBinary(void *, uint32); // Put binary data of any length 196 | uint32 GetSize(); // Get size of data added so far to current record 197 | protected: 198 | uint8 Type; // Record type 199 | uint32 Index; // Index to current offset 200 | uint32 RecordStart; // Index to start of current record 201 | }; 202 | 203 | 204 | // Structure for temporary segment list used while building OMF file 205 | struct SOMFSegmentList { 206 | public: 207 | uint32 NewNumber; // Segment index in new file 208 | uint32 OldName; // Segment name in old file as index into NameBuffer 209 | uint32 NewName; // Segment name in new file as index into NameBuffer 210 | uint32 NewNameI; // Segment name in new file as index into LNAMES record. Zero for subsequent entries with same segment name 211 | SCOFF_SectionHeader * psechdr; // Pointer to old section header 212 | uint32 Align; // Alignment = 2^Align 213 | uint32 Class; // Class in new file 214 | uint32 Offset; // Offset of section in old file to first section with same name 215 | uint32 Size; // Size of section. First record has combined size of all sections with same name 216 | uint32 SegmentSize; // Size of segment = combined size of all sections with same name. Stored only in first section of segment 217 | }; 218 | 219 | 220 | // Structure for temporary symbol list used while building OMF file 221 | struct SOMFSymbolList { 222 | public: 223 | uint32 Scope; // 0 = local, 1 = public, 2 = external 224 | uint32 NewIndex; // PUBDEF index if Scope = 1, EXTDEF index if scope = 2 225 | uint32 Segment; // New segment index 226 | uint32 Offset; // Offset relative to segment = first section with same name 227 | uint32 Name; // Symbol name in new file as index into NameBuffer 228 | }; 229 | 230 | 231 | // Structure for temporary relocation (fixup) list used while building OMF file 232 | struct SOMFRelocation { 233 | public: 234 | uint32 Section; // Section number in old file 235 | uint32 SourceOffset; // Offset of source relative to section 236 | int32 Mode; // 0 = EIP-relative, 1 = direct, -1 = unsupported 237 | uint32 Scope; // 0 = local, 2 = external 238 | uint32 TargetSegment; // Segment index or EXTDEF index of target in new file 239 | uint32 TargetOffset; // Offset relative to segment in new file of target 240 | int operator < (SOMFRelocation const & x) const {// operator < for sorting by CSList::Sort() 241 | return Section < x.Section || (Section == x.Section && SourceOffset < x.SourceOffset); 242 | } 243 | }; 244 | 245 | // Structure for assigning names to unnamed local symbols while converting OMF file 246 | struct SOMFLocalSymbol { 247 | uint32 Offset; // Offset into segment 248 | uint32 Segment; // Segment number in old file 249 | uint32 Name; // Assigned name as index into new string table 250 | uint32 NewSymtabIndex; // Index into new symbol table 251 | // Operator < needed for sorting table of SOMFLocalSymbol: 252 | int operator < (const SOMFLocalSymbol & b) const { 253 | return Segment < b.Segment || (Segment == b.Segment && Offset < b.Offset); 254 | } 255 | }; 256 | 257 | // Structure for interpreted SEGDEF record used during disassembly 258 | struct SOMFSegment { 259 | uint32 NameO; // Segment name, as offset into NameBuffer 260 | uint32 Offset; // Segment address 261 | uint32 Size; // Segment size 262 | uint32 Align; // Alignment = 1 << Align 263 | uint32 Type; // Segment type (as defined in disasm.h) 264 | uint32 WordSize; // 16 or 32 bits 265 | uint32 BufOffset; // Offset of raw data into SegmentData buffer 266 | uint32 NameIndex; // Name index, used for COMDAT segment only 267 | }; 268 | 269 | #endif // #ifndef OMF_H 270 | -------------------------------------------------------------------------------- /src/error.cpp: -------------------------------------------------------------------------------- 1 | /**************************** error.cpp ********************************** 2 | * Author: Agner Fog 3 | * Date created: 2006-07-15 4 | * Last modified: 2009-12-20 5 | * Project: objconv 6 | * Module: error.cpp 7 | * Description: 8 | * Standard procedure for error reporting to stderr 9 | * 10 | * Copyright 2006-2009 GNU General Public License http://www.gnu.org/licenses 11 | *****************************************************************************/ 12 | 13 | // Define this if you get problems: 14 | // #define OBJCONV_ERROR_CPP 1 15 | 16 | 17 | #include "stdafx.h" 18 | 19 | #define MAX_ERROR_TEXT_LENGTH 1024 // Maximum length of error text including extra info 20 | 21 | 22 | // Make and initialize error reporter object 23 | CErrorReporter err; 24 | 25 | SErrorText ErrorTexts[] = { 26 | // Unknown error 27 | {0, 2, "Unknown error number!"}, 28 | 29 | // Warning messages 30 | {1001, 1, "Empty command line option"}, 31 | {1002, 1, "Unknown command line option: %s"}, 32 | {1003, 1, "Unknown warning/error number: %i"}, 33 | {1006, 1, "Nothing do do. Copying file unchanged"}, 34 | {1008, 1, "Converting COFF file to ELF and back again."}, 35 | {1009, 1, "Converting OMF file to COFF and back again."}, 36 | {1010, 1, "Section index and section-relative fixup not supported in ELF file. Probably a debug record"}, 37 | {1011, 1, "Converting Mach-O file to ELF and back again."}, 38 | {1020, 1, "Non-public symbol %s cannot be made weak"}, 39 | {1021, 1, "Non-public symbol %s cannot be made local"}, 40 | {1022, 1, "Non-public symbol %s cannot get an alias"}, 41 | {1023, 1, "External symbol %s made local. Access to this symbol will cause error"}, 42 | {1024, 1, "Cannot change prefix on name %s, not a symbol"}, 43 | {1029, 1, "Debug information may be incompatible"}, 44 | {1030, 1, "Exception information may be incompatible"}, 45 | {1031, 1, "Windows resource information not translated"}, 46 | {1032, 1, "More than one symbol table found in ELF file"}, 47 | {1033, 1, "Sorry, cannot currently make alias in dynamic symbol table. Symbol = %s"}, 48 | {1040, 1, "Name of section %s too long. Truncating to 16 characters"}, 49 | {1050, 0, "Position dependent references will not work in .so file. (First occurrence is symbol %s. This message can be turned off with -wd1050)"}, 50 | {1051, 1, "Weak public not supported in target file type, symbol %s"}, 51 | {1052, 1, "Indirect symbol index out of range"}, 52 | {1053, 1, "Common constant converted to public: %s"}, 53 | {1054, 1, "Cannot find import table"}, 54 | {1055, 1, "Communal section currently not supported by objconv. Section dropped"}, 55 | {1060, 1, "Different alignments specified for same segment, %s. Using highest alignment"}, 56 | {1061, 1, "Symbol %s has lazy binding"}, 57 | {1062, 1, "Symbol %s has unknown type"}, 58 | {1063, 1, "Gnu indirect function (CPU dispatcher) cannot be converted"}, 59 | {1101, 1, "Output file name should have extension .lib or .a"}, 60 | {1102, 1, "Library members have different type"}, 61 | {1103, 1, "Output file name ignored"}, 62 | {1104, 1, "Library member %s not found. Extraction failed"}, 63 | {1106, 1, "Symbol %s not found. Modification of this symbol failed"}, 64 | {1107, 1, "Name of library member %s should have extension .o or .obj"}, 65 | {1108, 1, "Name of library member %s too long. Truncating to 15 characters"}, 66 | {1150, 1, "Universal binary contains more than one component that can be converted. Specify desired word size or use lipo to extract desired component"}, 67 | {1151, 1, "Skipping component with wordsize %i"}, 68 | 69 | {1202, 1, "OMF Record checksum error"}, 70 | {1203, 1, "Unrecognized data in OMF subrecord"}, 71 | {1204, 1, "String too long building OMF file. Truncating to 255 characters: %s"}, 72 | {1205, 1, "Alignment by %i possibly not supported for OMF file. Using page alignment (256 or 4096 depending on system)"}, 73 | {1206, 1, "Stack segment ignored"}, 74 | {1207, 1, "Overlapping data"}, 75 | {1208, 1, "Back-patched code (possibly OK)"}, 76 | {1211, 1, "%i comment records ignored"}, 77 | {1212, 1, "Record type (%s) not supported"}, 78 | {1213, 1, "Hash table has %i occurrences of name %s"}, 79 | {1214, 1, "Symbol %s defined in both modules %s"}, 80 | {1215, 1, "More than 251 blocks required in symbol hash table. May fail with some linkers"}, 81 | {1300, 1, "File contains 32-bit absolute address. Must link with option -image_base %s -pagezero_size 1000"}, 82 | {1301, 1, "Image-relative address converted to absolute. Assumes image base = %s"}, 83 | {1302, 1, "64-bit relocation with arbitrary reference point converted to 32-bit self-relative. Will fail if offset is negative"}, 84 | {1303, 1, "Cannot find imported symbol"}, 85 | {1304, 1, "Unknown relocation address"}, 86 | 87 | // Error messages 88 | {2001, 2, "No more than one input file and one output file can be specified"}, 89 | {2002, 2, "Word size (%i) not supported for output file"}, 90 | {2003, 2, "Only one output format option can be specified. Command line error at %s"}, 91 | {2004, 2, "Unknown command line option: %s"}, 92 | {2005, 2, "Input file and output file cannot have same name: %s"}, 93 | {2006, 2, "Unsupported file type for file %s: %s"}, 94 | {2007, 2, "Cannot dump and convert file in the same command"}, 95 | {2008, 2, "This option must have two symbol names: %s"}, 96 | {2009, 2, "This option must have one symbol name: %s"}, 97 | {2010, 2, "Sorry. Dump of file type %s is not supported"}, 98 | {2011, 2, "Sorry. Conversion of file type %s is not supported"}, 99 | {2012, 2, "Cannot convert from word size %i to word size %i"}, 100 | {2013, 2, "Sorry. Conversion of file type %s to %s is not supported"}, 101 | {2014, 2, "File contains information for .NET common language runtime. Cannot convert"}, 102 | {2015, 2, "More than one option specified for symbol %s"}, 103 | {2016, 2, "Index out of range"}, 104 | {2017, 2, "File name %s specified more than once"}, 105 | {2018, 2, "Unknown type for file: %s"}, 106 | {2020, 2, "Overflow when converting value of symbol %s to 32 bits"}, 107 | {2021, 2, "File contains information for objective-C runtime code. Cannot convert"}, 108 | {2022, 2, "Cannot convert executable file"}, 109 | 110 | {2030, 2, "Unsupported relocation type (%i)"}, 111 | {2031, 2, "Relocated symbol not found"}, 112 | {2032, 2, "Relocation points outside segment"}, 113 | {2033, 2, "Error in ELF file. Record size not specified"}, 114 | {2034, 2, "Symbol table not found in ELF file"}, 115 | {2035, 2, "Pointer out of range in object file"}, 116 | {2036, 2, "Unknown section index in ELF file: %i"}, 117 | {2037, 2, "Symbol storage/binding type %i not supported"}, 118 | {2038, 2, "Symbol type %i not supported"}, 119 | {2040, 2, "Symbol table corrupt in object file"}, 120 | {2041, 2, "File has relocation of uninitialized data"}, 121 | {2042, 2, "Relocation to global offset table found. Cannot convert position-independent code"}, 122 | {2043, 2, "Relocation to procedure linkage table found. Cannot convert"}, 123 | {2044, 2, "Relocation relative to arbitrary reference point that cannot be converted"}, 124 | {2045, 2, "Unknown import table type"}, 125 | {2050, 2, "Inconsistent relocation record pair"}, 126 | {2051, 2, "Too many symbols for Mach-O file. Maximum = 16M"}, 127 | {2052, 2, "Unexpected data between symbol table and string table"}, 128 | 129 | {2103, 2, "Cannot read input file %s"}, 130 | {2104, 2, "Cannot write output file %s"}, 131 | {2105, 2, "Wrong size of file %s"}, 132 | {2107, 2, "Too many response files"}, 133 | {2110, 2, "COFF file section table corrupt"}, 134 | {2112, 2, "String table corrupt"}, 135 | {2114, 2, "This is an intermediate file for whole-program-optimization in Intel compiler"}, 136 | {2201, 2, "Not enough space for new file name %s. Please make this name shorter"}, 137 | {2202, 2, "Symbol name %s too long. Cannot change prefix"}, 138 | {2210, 2, "File contains overlapping relocation sources"}, 139 | {2301, 2, "OMF Record extends beyond end of file"}, 140 | {2302, 2, "Fixup source extends beyond end of section"}, 141 | {2303, 2, "Too many symbols for OMF file. Index exceeds 32767"}, 142 | {2304, 2, "Word-size index exceeds 65535"}, 143 | {2305, 2, "%i Communal sections found. Currently not supported by Objconv"}, 144 | {2306, 2, "Segment size is 4 Gbytes"}, 145 | {2307, 2, "Segment address is absolute"}, 146 | {2308, 2, "Unknown alignment %i"}, 147 | {2309, 2, "Data outside bounds of segment %s"}, 148 | {2310, 2, "Iterated data outside bounds of segment"}, 149 | {2311, 2, "Relocation of iterated data not supported by objconv"}, 150 | {2312, 2, "FIXUPP record does not refer to data record"}, 151 | {2313, 2, "OMF file has compression of repeated relocation target (thread). This is not supported in objconv"}, 152 | {2314, 2, "Unknown relocation method T%i"}, 153 | {2315, 2, "Group-relative relocation to %s not supported"}, 154 | {2316, 2, "Incompatible relocation method: %s"}, 155 | {2317, 2, "Incompatible word size: %i"}, 156 | {2318, 2, "OMF file has compression of repeated communal data. This is not supported in objconv"}, 157 | {2320, 2, "Mixed 32-bit and 64-bit segments"}, 158 | {2321, 2, "Wrong record size found"}, 159 | {2330, 2, "Imagebase specified more than once"}, 160 | {2331, 2, "Imagebase must be divisible by page size 1000 (hexadecimal)"}, 161 | {2332, 2, "Imagebase must > 0 and < 80000000 (hexadecimal)"}, 162 | 163 | {2500, 2, "Library/archive file is corrupt"}, 164 | {2501, 2, "Cannot store file of type %s in library"}, 165 | {2502, 2, "Too many members in library"}, 166 | {2503, 2, "Output file name must be specified"}, 167 | {2504, 2, "Object file type (%s) does not match library"}, 168 | {2505, 2, "Object file word size (%i) does not match library"}, 169 | {2506, 2, "Overflow of buffer for library member names"}, 170 | {2507, 2, "%s is an import library. Cannot convert to static library"}, 171 | {2600, 2, "Library has more than one header"}, 172 | {2601, 2, "Library page size (%i) is not a power of 2"}, 173 | {2602, 2, "Library end record does not match dictionary offset in OMF library"}, 174 | {2603, 2, "Public name %s not found in hash table"}, 175 | {2605, 2, "Symbol hash table too big. Creation of library failed"}, 176 | {2606, 2, "Too many library members. Creation of library failed"}, 177 | {2610, 2, "Library end record not found"}, 178 | {2620, 2, "You need to extract library members before disassembling"}, 179 | {2621, 2, "Wrong output file type"}, 180 | 181 | {2701, 2, "Wrong number of members in universal binary (%i)"}, 182 | 183 | {3000, 1, "Internal error in opcode table"}, 184 | {3001, 1, "Internal error: Unknown register type 0x%X"}, 185 | 186 | // Fatal errors makes the program stop immediately: 187 | {9000, 9, "Objconv program internal inconsistency"}, 188 | {9001, 9, "Objconv program has been compiled with wrong integer sizes"}, 189 | {9002, 9, "Objconv cannot run on machine with big-endian memory organization"}, 190 | {9003, 9, "Array index out of range"}, 191 | {9004, 9, "Cannot resize array of type CArrayBuf"}, 192 | {9005, 9, "Exceeding 1kb size limit while building OMF record"}, 193 | {9006, 9, "Memory allocation failed"}, 194 | {9007, 9, "Objcopy internal error in opcode map 0x%X"}, 195 | 196 | // Mark end of list 197 | {9999, 9999, "End of error text list"} 198 | }; 199 | 200 | 201 | // Constructor for CErrorReporter 202 | CErrorReporter::CErrorReporter() { 203 | NumErrors = NumWarnings = WorstError = 0; 204 | MaxWarnings = 50; // Max number of warning messages to pring 205 | MaxErrors = 50; // Max number of error messages to print 206 | } 207 | 208 | SErrorText * CErrorReporter::FindError(int ErrorNumber) { 209 | // Search for error in ErrorTexts 210 | int e; 211 | const int ErrorTextsLength = sizeof(ErrorTexts) / sizeof(ErrorTexts[0]); 212 | for (e = 0; e < ErrorTextsLength; e++) { 213 | if (ErrorTexts[e].ErrorNumber == ErrorNumber) return ErrorTexts + e; 214 | } 215 | // Error number not found 216 | static SErrorText UnknownErr = ErrorTexts[0]; 217 | UnknownErr.ErrorNumber = ErrorNumber; 218 | UnknownErr.Status = 0x102; // Unknown error 219 | return &UnknownErr; 220 | } 221 | 222 | 223 | void CErrorReporter::submit(int ErrorNumber) { 224 | // Print error message with no extra info 225 | SErrorText * err = FindError(ErrorNumber); 226 | HandleError(err, err->Text); 227 | } 228 | 229 | void CErrorReporter::submit(int ErrorNumber, int extra) { 230 | // Print error message with extra numeric info 231 | // ErrorTexts[ErrorNumber] must contain %i where extra is to be inserted 232 | char text[MAX_ERROR_TEXT_LENGTH]; 233 | SErrorText * err = FindError(ErrorNumber); 234 | sprintf(text, err->Text, extra); 235 | HandleError(err, text); 236 | } 237 | 238 | void CErrorReporter::submit(int ErrorNumber, int extra1, int extra2) { 239 | // Print error message with 2 extra numeric values inserted 240 | // ErrorTexts[ErrorNumber] must contain two %i fields where extra numbers are to be inserted 241 | char text[MAX_ERROR_TEXT_LENGTH]; 242 | SErrorText * err = FindError(ErrorNumber); 243 | sprintf(text, err->Text, extra1, extra2); 244 | HandleError(err, text); 245 | } 246 | 247 | void CErrorReporter::submit(int ErrorNumber, char const * extra) { 248 | // Print error message with extra text info 249 | // ErrorTexts[ErrorNumber] must contain %s where extra is to be inserted 250 | char text[MAX_ERROR_TEXT_LENGTH]; 251 | if (extra == 0) extra = "???"; 252 | SErrorText * err = FindError(ErrorNumber); 253 | sprintf(text, err->Text, extra); 254 | HandleError(err, text); 255 | } 256 | 257 | void CErrorReporter::submit(int ErrorNumber, char const * extra1, char const * extra2) { 258 | // Print error message with two extra text info fields 259 | // ErrorTexts[ErrorNumber] must contain %s where extra texts are to be inserted 260 | char text[MAX_ERROR_TEXT_LENGTH]; 261 | if (extra1 == 0) extra1 = "???"; if (extra2 == 0) extra2 = "???"; 262 | SErrorText * err = FindError(ErrorNumber); 263 | sprintf(text, err->Text, extra1, extra2); 264 | HandleError(err, text); 265 | } 266 | 267 | void CErrorReporter::submit(int ErrorNumber, int extra1, char const * extra2) { 268 | // Print error message with two extra text fields inserted 269 | // ErrorTexts[ErrorNumber] must contain %i and %s where extra texts are to be inserted 270 | char text[MAX_ERROR_TEXT_LENGTH]; 271 | if (extra2 == 0) extra2 = "???"; 272 | SErrorText * err = FindError(ErrorNumber); 273 | sprintf(text, err->Text, extra1, extra2); 274 | HandleError(err, text); 275 | } 276 | 277 | void CErrorReporter::HandleError(SErrorText * err, char const * text) { 278 | // HandleError is used by submit functions 279 | // check severity 280 | int severity = err->Status & 0x0F; 281 | if (severity == 0) { 282 | return; // Ignore message 283 | } 284 | if (severity > 1 && err->ErrorNumber > WorstError) { 285 | // Store highest error number 286 | WorstError = err->ErrorNumber; 287 | } 288 | if (severity == 1) { 289 | // Treat message as warning 290 | if (++NumWarnings > MaxWarnings) return; // Maximum number of warnings has been printed 291 | // Treat message as warning 292 | fprintf(stderr, "\nWarning %i: %s", err->ErrorNumber, text); 293 | if (NumWarnings == MaxWarnings) { 294 | // Maximum number reached 295 | fprintf(stderr, "\nSupressing further warning messages"); 296 | } 297 | } 298 | else { 299 | // Treat message as error 300 | if (++NumErrors > MaxErrors) return; // Maximum number of warnings has been printed 301 | fprintf(stderr, "\nError %i: %s", err->ErrorNumber, text); 302 | if (NumErrors == MaxErrors) { 303 | // Maximum number reached 304 | fprintf(stderr, "\nSupressing further warning messages"); 305 | } 306 | } 307 | if (severity == 9) { 308 | // Abortion required 309 | fprintf(stderr, "\nAborting\n"); 310 | exit(err->ErrorNumber); 311 | } 312 | } 313 | 314 | int CErrorReporter::Number() { 315 | // Get number of fatal errors 316 | return NumErrors; 317 | } 318 | 319 | int CErrorReporter::GetWorstError() { 320 | // Get highest warning or error number encountered 321 | return WorstError; 322 | } 323 | 324 | void CErrorReporter::ClearError(int ErrorNumber) { 325 | // Ignore further occurrences of this error 326 | int e; 327 | const int ErrorTextsLength = sizeof(ErrorTexts) / sizeof(ErrorTexts[0]); 328 | for (e = 0; e < ErrorTextsLength; e++) { 329 | if (ErrorTexts[e].ErrorNumber == ErrorNumber) break; 330 | } 331 | if (e < ErrorTextsLength) { 332 | ErrorTexts[e].Status = 0; 333 | } 334 | } 335 | -------------------------------------------------------------------------------- /src/mac2mac.cpp: -------------------------------------------------------------------------------- 1 | /**************************** mac2mac.cpp ***************************** 2 | * Author: Agner Fog 3 | * Date created: 2008-05-25 4 | * Last modified: 2008-05-25 5 | * Project: objconv 6 | * Module: mac2mac.cpp 7 | * Description: 8 | * Module for changing symbol names in Mach-O file 9 | * 10 | * Copyright 2008 GNU General Public License http://www.gnu.org/licenses 11 | *****************************************************************************/ 12 | #include "stdafx.h" 13 | // All functions in this module are templated to make two versions: 32 and 64 bits. 14 | // See instantiations at the end of this file. 15 | 16 | 17 | // Constructor 18 | template 19 | CMAC2MAC::CMAC2MAC() { 20 | // Initialize everything 21 | memset(this, 0, sizeof(*this)); 22 | } 23 | 24 | 25 | // Convert() 26 | template 27 | void CMAC2MAC::Convert() { 28 | MakeSymbolTable(); // Remake symbol tables and string tables 29 | MakeBinaryFile(); // Put everyting together into ToFile 30 | ChangeSegments(); // Modify section names and relocation table symbol indices 31 | *this << ToFile; // Take over new file buffer 32 | } 33 | 34 | 35 | // MakeSymbolTable() 36 | template 37 | void CMAC2MAC::MakeSymbolTable() { 38 | // Remake symbol tables and string table 39 | int OldScope = 0; // Old scope of symbol. 0=local, 1=public, 2=external 40 | int NewScope; // New scope of symbol. 0=local, 1=public, 2=external 41 | uint32 symi; // Old index of symbol 42 | const char * Name1; // Old symbol name 43 | const char * Name2; // New symbol name 44 | int action; // Action to take on symbol 45 | int SymType; // Symbol type 46 | int SymDesc; // Symbol descriptor 47 | uint8 Section; // Symbol section 48 | 49 | // pointer to symbol table 50 | TMAC_nlist * symp = (TMAC_nlist*)(this->Buf() + this->SymTabOffset); 51 | 52 | // pointer to string table 53 | char * strtab = (char*)(this->Buf() + this->StringTabOffset); 54 | 55 | // loop through symbol table 56 | for (symi = 0; symi < this->SymTabNumber; symi++, symp++) { 57 | 58 | // Check indices for first symbol of each scope category 59 | if (symi == this->iextdefsym && this->nextdefsym) OldScope = 1; 60 | if (symi == this->iundefsym && this->nundefsym) OldScope = 2; 61 | NewScope = OldScope; 62 | 63 | if (symp->n_strx >= this->StringTabSize) { 64 | // Index out of range 65 | err.submit(2112); continue; 66 | } 67 | 68 | // Get symbol name 69 | Name1 = strtab + symp->n_strx; 70 | 71 | // Get type, descriptor and section 72 | SymType = symp->n_type; // Symbol type 73 | SymDesc = symp->n_desc; // Symbol descriptor 74 | Section = symp->n_sect; // Symbol section 75 | 76 | // Check if any change required for this symbol 77 | action = cmd.SymbolChange(Name1, &Name2, SYMT_LOCAL + OldScope); 78 | 79 | switch (action) { 80 | case SYMA_NOCHANGE: 81 | // No change 82 | break; 83 | 84 | case SYMA_MAKE_WEAK: 85 | // Make symbol weak 86 | if (cmd.OutputType == FILETYPE_COFF) { 87 | // PE/COFF format does not support weak publics 88 | err.submit(2200); 89 | } 90 | // Make weak 91 | if (OldScope == 1) { 92 | SymDesc |= MAC_N_WEAK_DEF; // Weak public. Allowed only in coalesced (communal) section 93 | } 94 | else if (OldScope == 2) { 95 | SymDesc |= MAC_N_WEAK_REF; // Weak external 96 | } 97 | else { 98 | err.submit(1020, Name1); // Local symbol 99 | } 100 | break; 101 | 102 | case SYMA_MAKE_LOCAL: 103 | // Make public symbol local, make external symbol ignored 104 | if (OldScope == 1) { 105 | NewScope = 0; // Public changed to local 106 | SymType &= ~MAC_N_EXT; 107 | } 108 | else if (OldScope == 2) { 109 | Section = MAC_NO_SECT; // External symbol. Set to 0 110 | SymDesc = 0; 111 | SymType = MAC_N_UNDF; 112 | } 113 | else err.submit(1021, Name1); 114 | break; 115 | 116 | case SYMA_CHANGE_NAME: 117 | // Change name of symbol 118 | Name1 = Name2; Name2 = 0; 119 | break; 120 | 121 | case SYMA_CHANGE_ALIAS: 122 | // Make alias and keep old name 123 | if (OldScope != 1) { 124 | err.submit(1022, Name1); break; 125 | } 126 | // Make alias 127 | NewSymbols[1].AddSymbol(-1, Name2, SymType, SymDesc, Section, symp->n_value); 128 | break; 129 | 130 | default: 131 | err.submit(9000); // unknown error 132 | } 133 | 134 | // Store symbol, possibly modified 135 | NewSymbols[NewScope].AddSymbol(symi, Name1, SymType, SymDesc, Section, symp->n_value); 136 | } 137 | 138 | // Put everything into symbol table and string table 139 | for (NewScope = 0; NewScope < 3; NewScope++) { 140 | NewSymbols[NewScope].SortList(); // Sort each list alphabetically 141 | NewSymbols[NewScope].StoreList(&NewSymbolTable, &NewStringTable); 142 | } 143 | 144 | // Indices to local, public and external symbols 145 | NewIlocalsym = 0; // index to local symbols 146 | NewNlocalsym = NewSymbols[0].GetNumEntries(); // number of local symbols 147 | NewIextdefsym = NewNlocalsym; // index to public symbols 148 | NewNextdefsym = NewSymbols[1].GetNumEntries();// number of public symbols 149 | NewIundefsym = NewNlocalsym + NewNextdefsym; // index to external symbols 150 | NewNundefsym = NewSymbols[2].GetNumEntries(); // number of external symbols 151 | 152 | // Calculate difference in size of new tables versus old tables 153 | // (this calculation is moved to MakeBinaryFile) 154 | // SizeDifference = NewSymbolTable.GetDataSize + NewStringTable.GetDataSize() 155 | // - this->SymTabNumber * sizeof(TMAC_nlist) - this->StringTabSize; 156 | } 157 | 158 | template 159 | int CMAC2MAC::NewSymbolIndex(int32 OldIndex) { 160 | // Convert subfunction: Translate old to new symbol index 161 | int NewIndex; 162 | int Scope; 163 | // Search for symbol in all scopes 164 | for (Scope = 0; Scope < 3; Scope++) { 165 | NewIndex = NewSymbols[Scope].TranslateIndex(OldIndex); 166 | if (NewIndex >= 0) { 167 | // OldIndex found. Add offset into appropriate table 168 | if (Scope == 1) NewIndex += NewIextdefsym; 169 | else if (Scope == 2) NewIndex += NewIundefsym; 170 | return NewIndex; 171 | } 172 | } 173 | //err.submit(2031); 174 | return -1; 175 | } 176 | 177 | 178 | template 179 | uint32 CMAC2MAC::NewFileOffset(uint32 OldOffset) { 180 | // Convert subfunction: Translate old to new file offset 181 | if (OldOffset <= NewSymtabOffset) { 182 | // Before symbol table. No change 183 | return OldOffset; 184 | } 185 | if (OldOffset >= OldTablesEnd) { 186 | // After string table. Add size difference 187 | return OldOffset + SizeDifference; 188 | } 189 | // Between symbol table and string table. 190 | // The possibility of something between these two tables has not been accounted for 191 | err.submit(2052); 192 | return 0; 193 | } 194 | 195 | 196 | // MakeBinaryFile() 197 | template 198 | void CMAC2MAC::MakeBinaryFile() { 199 | uint32 OldSymtabEnd; // End of old symbol table 200 | uint32 OldStringtabEnd; // End of old string table 201 | const int WordSize = sizeof(MInt) * 8; // Word size, 32 or 64 bits 202 | 203 | // Offset to symbol table and string table 204 | NewSymtabOffset = this->SymTabOffset; 205 | if (this->StringTabOffset && this->StringTabOffset < NewSymtabOffset) NewSymtabOffset = this->StringTabOffset; 206 | if (NewSymtabOffset == 0) NewSymtabOffset = this->GetDataSize(); 207 | 208 | // Copy all headers and all data until TablesOffset 209 | ToFile.Push(this->Buf(), NewSymtabOffset); 210 | ToFile.Align(WordSize/8); 211 | NewSymtabOffset = ToFile.GetDataSize(); 212 | 213 | // Copy new symbol table 214 | ToFile.Push(NewSymbolTable.Buf(), NewSymbolTable.GetDataSize()); 215 | 216 | // Copy new string table 217 | NewStringtabOffset = ToFile.GetDataSize(); 218 | ToFile.Push(NewStringTable.Buf(), NewStringTable.GetDataSize()); 219 | ToFile.Align(2); 220 | NewStringtabEnd = ToFile.GetDataSize(); 221 | 222 | // Find end of old tables 223 | OldSymtabEnd = this->SymTabOffset + this->SymTabNumber * sizeof(TMAC_nlist); 224 | OldStringtabEnd = this->StringTabOffset + this->StringTabSize; 225 | OldTablesEnd = OldStringtabEnd; 226 | if (OldSymtabEnd > OldTablesEnd) OldTablesEnd = OldSymtabEnd; 227 | if (OldTablesEnd == 0) OldTablesEnd = this->GetDataSize(); 228 | 229 | // Size difference between new and old tables 230 | SizeDifference = NewStringtabEnd - OldTablesEnd; 231 | 232 | // Is there anything in the old file after these tables? 233 | if (OldTablesEnd && this->GetDataSize() > OldTablesEnd) { 234 | // There is something after these tables. Copy it 235 | ToFile.Push(this->Buf() + OldTablesEnd, this->GetDataSize() - OldTablesEnd); 236 | } 237 | } 238 | 239 | 240 | // ChangeSegments() 241 | template 242 | void CMAC2MAC::ChangeSegments() { 243 | // Convert subfunction: Change section names if needed and adjust all relocation tables 244 | 245 | uint32 FileOffset; // Current offset into file 246 | uint32 lcmd; // Load command 247 | uint32 cmdsize = 0; // Command size 248 | uint32 icmd; // Loop counter 249 | int action; // Name change action 250 | char * Name1; // Old name 251 | const char * Name2; // New name 252 | 253 | FileOffset = sizeof(TMAC_header); 254 | // Loop through file commands 255 | for (icmd = 1; icmd <= this->FileHeader.ncmds; icmd++, FileOffset += cmdsize) { 256 | lcmd = ((MAC_load_command*)(ToFile.Buf() + FileOffset)) -> cmd; 257 | cmdsize = ((MAC_load_command*)(ToFile.Buf() + FileOffset)) -> cmdsize; 258 | 259 | // Interpret specific command type 260 | switch(lcmd) { 261 | case MAC_LC_SEGMENT: { // 32-bit segment 262 | MAC_segment_command_32 * sh = (MAC_segment_command_32*)(ToFile.Buf() + FileOffset); 263 | Name1 = sh->segname; 264 | // Check if any change required for this symbol 265 | action = cmd.SymbolChange(Name1, &Name2, SYMT_SECTION); 266 | if (action == SYMA_CHANGE_NAME) { 267 | // Change segment name 268 | if (strlen(Name2) > 16) err.submit(1040); 269 | strncpy(Name1, Name2, 16); 270 | } 271 | // Change section names and relocations in all sections under this segment 272 | ChangeSections(FileOffset + sizeof(MAC_segment_command_32), sh->nsects); 273 | break;} 274 | 275 | case MAC_LC_SEGMENT_64: { // 64-bit segment 276 | MAC_segment_command_64 * sh = (MAC_segment_command_64*)(ToFile.Buf() + FileOffset); 277 | Name1 = sh->segname; 278 | // Check if any change required for this symbol 279 | action = cmd.SymbolChange(Name1, &Name2, SYMT_SECTION); 280 | if (action == SYMA_CHANGE_NAME) { 281 | // Change segment name 282 | if (strlen(Name2) > 16) err.submit(1040); 283 | strncpy(Name1, Name2, 16); 284 | } 285 | // Change section names and relocations in all sections under this segment 286 | ChangeSections(FileOffset + sizeof(MAC_segment_command_64), sh->nsects); 287 | break;} 288 | 289 | case MAC_LC_SYMTAB: { // Symbol table header 290 | MAC_symtab_command * sh = (MAC_symtab_command*)(ToFile.Buf() + FileOffset); 291 | // Change table addresses 292 | sh->symoff = NewSymtabOffset; 293 | sh->nsyms = NewSymbolTable.GetDataSize() / sizeof(TMAC_nlist); 294 | sh->stroff = NewStringtabOffset; 295 | sh->strsize = NewStringtabEnd - NewStringtabOffset; 296 | break;} 297 | 298 | case MAC_LC_DYSYMTAB: { // dynamic link-edit symbol table 299 | MAC_dysymtab_command * sh = (MAC_dysymtab_command*)(ToFile.Buf() + FileOffset); 300 | // Change indices to symbol tables 301 | sh->ilocalsym = NewIlocalsym; 302 | sh->nlocalsym = NewNlocalsym; 303 | sh->iextdefsym = NewIextdefsym; 304 | sh->nextdefsym = NewNextdefsym; 305 | sh->iundefsym = NewIundefsym; 306 | sh->nundefsym = NewNundefsym; 307 | 308 | // Change table addresses 309 | sh->tocoff = NewFileOffset(sh->tocoff); 310 | sh->modtaboff = NewFileOffset(sh->modtaboff); 311 | sh->extrefsymoff = NewFileOffset(sh->extrefsymoff); 312 | sh->indirectsymoff = NewFileOffset(sh->indirectsymoff); 313 | sh->extreloff = NewFileOffset(sh->extreloff); 314 | sh->locreloff = NewFileOffset(sh->locreloff); 315 | 316 | if (sh->nindirectsyms) { 317 | // Change symbol indices in import table 318 | ChangeImportTable(sh->indirectsymoff, sh->nindirectsyms); 319 | } 320 | break;} 321 | } 322 | } 323 | } 324 | 325 | 326 | template 327 | void CMAC2MAC::ChangeSections(uint32 HeaderOffset, uint32 Num) { 328 | // Convert subfunction: Change section names and relocation records if needed 329 | int action; // Name change action 330 | char * Name1; // Old name 331 | const char * Name2; // New name 332 | uint32 isec1; // Section index 333 | TMAC_section * secp; // Pointer to section header 334 | uint32 irel; // Relocation index 335 | MAC_relocation_info * relp; // Pointer to relocation record 336 | 337 | // Loop through section headers 338 | for (isec1 = 0; isec1 < Num; isec1++) { 339 | // Find section header 340 | secp = (TMAC_section*)(ToFile.Buf() + HeaderOffset + isec1*sizeof(TMAC_section)); 341 | 342 | // Segment name 343 | Name1 = secp->segname; 344 | action = cmd.SymbolChange(Name1, &Name2, SYMT_SECTION); 345 | if (action == SYMA_CHANGE_NAME) { 346 | // Change segment name 347 | if (strlen(Name2) > 16) err.submit(1040); 348 | strncpy(Name1, Name2, 16); 349 | } 350 | 351 | // Section name 352 | Name1 = secp->sectname; 353 | action = cmd.SymbolChange(Name1, &Name2, SYMT_SECTION); 354 | if (action == SYMA_CHANGE_NAME) { 355 | // Change section name 356 | if (strlen(Name2) > 16) err.submit(1040); 357 | strncpy(Name1, Name2, 16); 358 | } 359 | 360 | // Update file offset 361 | secp->offset = NewFileOffset(secp->offset); 362 | 363 | if (secp->nreloc) { 364 | // This section has relocations 365 | // Update relocations offset 366 | secp->reloff = NewFileOffset(secp->reloff); 367 | 368 | // Pointer to relocation records 369 | relp = (MAC_relocation_info*)(ToFile.Buf() + secp->reloff); 370 | 371 | // Loop through relocations, if any 372 | for (irel = 0; irel < secp->nreloc; irel++, relp++) { 373 | // Only non-scattered r_extern relocations have symbol index 374 | if (!(relp->r_address & R_SCATTERED) && relp->r_extern) { 375 | // Update symbol index 376 | relp->r_symbolnum = NewSymbolIndex(relp->r_symbolnum); 377 | } 378 | } 379 | } 380 | } 381 | } 382 | 383 | 384 | template 385 | void CMAC2MAC::ChangeImportTable(uint32 FileOffset, uint32 Num) { 386 | // Convert subfunction: Change symbol indices in import table if needed 387 | uint32 i; // Index 388 | uint32 * p; // pointer to current entry 389 | 390 | // Find first entry 391 | p = (uint32*)(ToFile.Buf() + FileOffset); 392 | 393 | // Loop through table 394 | for (i = 0; i < Num; i++, p++) { 395 | // Translate symbol index 396 | *p = NewSymbolIndex(*p); 397 | } 398 | } 399 | 400 | 401 | // Make template instances for 32 and 64 bits 402 | template class CMAC2MAC; 403 | template class CMAC2MAC; 404 | -------------------------------------------------------------------------------- /src/elf2elf.cpp: -------------------------------------------------------------------------------- 1 | /**************************** elf2elf.cpp ***************************** 2 | * Author: Agner Fog 3 | * Date created: 2006-01-13 4 | * Last modified: 2006-01-13 5 | * Project: objconv 6 | * Module: elf2elf.cpp 7 | * Description: 8 | * Module for changing symbol names in ELF file 9 | * 10 | * Copyright 2006-2008 GNU General Public License http://www.gnu.org/licenses 11 | *****************************************************************************/ 12 | #include "stdafx.h" 13 | // All functions in this module are templated to make two versions: 32 and 64 bits. 14 | // See instantiations at the end of this file. 15 | 16 | 17 | // Constructor 18 | template 19 | CELF2ELF::CELF2ELF() { 20 | // Initialize everything 21 | memset(this, 0, sizeof(*this)); 22 | } 23 | 24 | 25 | // Convert() 26 | template 27 | void CELF2ELF::Convert() { 28 | // Some compilers require this-> for accessing members of template base class, 29 | // according to the so-called two-phase lookup rule. 30 | MakeSymbolTable(); // Remake symbol tables and string tables 31 | ChangeSections(); // Modify section names and relocation table symbol indices 32 | MakeBinaryFile(); // Put everyting together into ToFile 33 | *this << ToFile; // Take over new file buffer 34 | } 35 | 36 | 37 | // MakeSymbolTable() 38 | template 39 | void CELF2ELF::MakeSymbolTable() { 40 | uint32 SectionNumber; // Section number 41 | char * SectionName; // Section name 42 | uint32 SecNamei; // Section name index 43 | uint32 OldSymi; // Old symbol index 44 | uint32 NewSymi; // New symbol index 45 | int isymt; // 0 = symtab, 1 = dynsym 46 | const char * name1; // Old name of symbol 47 | const char * name2; // Changed name of symbol 48 | int SymbolType; // Symbol type for cmd.SymbolChange 49 | int action; // Symbol change action 50 | int binding; // Symbol binding 51 | TELF_Symbol sym; // Symbol table entry 52 | TELF_Symbol AliasEntry; // Symbol table alias entry 53 | uint32 symnamei; // New symbol name index 54 | CMemoryBuffer TempGlobalSymbolTable; // Temporary storage of public and external symbols 55 | 56 | // Find symbol table and string tables 57 | for (SectionNumber = 0; SectionNumber < this->NSections; SectionNumber++) { 58 | // Get copy of 32-bit header or converted 64-bit header 59 | TELF_SectionHeader sheader = this->SectionHeaders[SectionNumber]; 60 | switch (sheader.sh_type) { 61 | case SHT_SYMTAB: 62 | isymtab[0] = SectionNumber; // Symbol table found 63 | istrtab[0] = this->SectionHeaders[SectionNumber].sh_link; // Associated string table 64 | break; 65 | 66 | case SHT_DYNSYM: 67 | isymtab[1] = SectionNumber; // Dynamic symbol table found 68 | istrtab[1] = this->SectionHeaders[SectionNumber].sh_link; // Associated string table 69 | break; 70 | 71 | case SHT_STRTAB: 72 | SecNamei = sheader.sh_name; 73 | if (SecNamei >= this->SecStringTableLen) 74 | err.submit(2112); 75 | SectionName = this->SecStringTable + SecNamei; 76 | if (SectionNumber == this->FileHeader.e_shstrndx || !strcmp(SectionName,".shstrtab")) { 77 | istrtab[2] = SectionNumber; // Section header string table found 78 | } 79 | else if (!strcmp(SectionName,".strtab") && !istrtab[0]) { 80 | istrtab[0] = SectionNumber; // Symbol string table found 81 | } 82 | else if (!strcmp(SectionName,".stabstr")) { 83 | istrtab[3] = SectionNumber; // Debug string table found 84 | } 85 | break; 86 | } 87 | } 88 | 89 | // Make new symbol tables and string tables 90 | // Loop through possibly two symbol tables 91 | for (isymt = 0; isymt < 2; isymt++) { 92 | 93 | if (isymtab[isymt] && isymtab[isymt] < this->NSections 94 | && istrtab[isymt] && istrtab[isymt] < this->NSections) { 95 | 96 | // Symbol table header 97 | uint32 SymTabHeaderOffset = uint32(this->FileHeader.e_shoff + isymtab[isymt] * this->SectionHeaderSize); 98 | //TELF_SectionHeader SymTabHeader = this->Get(SymTabHeaderOffset); 99 | // Some compilers fail with the double template here. Avoid the template: 100 | TELF_SectionHeader SymTabHeader = *(TELF_SectionHeader*)(this->Buf() + SymTabHeaderOffset); 101 | 102 | // Find symbol table 103 | uint32 symtabsize = (uint32)(SymTabHeader.sh_size); 104 | int8 * symtab = this->Buf() + SymTabHeader.sh_offset; 105 | int8 * symtabend = symtab + symtabsize; 106 | int entrysize = (int)(SymTabHeader.sh_entsize); 107 | if (entrysize <= 0) entrysize = sizeof(TELF_Symbol); 108 | 109 | // Find string table 110 | char * StringTable = this->Buf() + this->SectionHeaders[istrtab[isymt]].sh_offset; 111 | uint32 StringTableLen = uint32(this->SectionHeaders[istrtab[isymt]].sh_size); 112 | 113 | NewStringTable[isymt].Push(0, 1); // Initialize new string table, first entry 0 114 | 115 | if (isymt == 0) { 116 | // Allocate NewSymbolIndex 117 | NumOldSymbols = (symtabsize + entrysize - 1) / entrysize; // round up to nearest integer to be safe 118 | NewSymbolIndex.SetNum(NumOldSymbols); // Allocate array 119 | NewSymbolIndex.SetZero(); // Initialize 120 | } 121 | 122 | // Loop through old symbol table 123 | for (OldSymi = 0; symtab < symtabend; symtab += entrysize, OldSymi++) { 124 | 125 | // Symbol table entry 126 | sym = *(TELF_Symbol*)symtab; 127 | 128 | // Symbol name 129 | if (sym.st_name < StringTableLen) { 130 | name1 = StringTable + sym.st_name;} 131 | else { 132 | err.submit(2035); name1 = 0; 133 | } 134 | name2 = 0; 135 | 136 | // Symbol type 137 | int type = sym.st_type; 138 | binding = sym.st_bind; 139 | if (binding == STB_LOCAL) { 140 | SymbolType = SYMT_LOCAL; // Symbol is local 141 | } 142 | else if (type == STT_OBJECT || type == STT_FUNC || type == STT_NOTYPE) { 143 | if (int16(sym.st_shndx) > 0) { // Check section number 144 | SymbolType = SYMT_PUBLIC; // Symbol is public 145 | } 146 | else { 147 | SymbolType = SYMT_EXTERNAL; // Symbol is external 148 | } 149 | } 150 | else { 151 | SymbolType = SYMT_OTHER; // Symbol is section or filename or debug 152 | } 153 | 154 | // Check if any change required for this symbol 155 | action = cmd.SymbolChange(name1, &name2, SymbolType); 156 | 157 | switch (action) { 158 | case SYMA_NOCHANGE: 159 | // No change 160 | break; 161 | 162 | case SYMA_MAKE_WEAK: 163 | // Make symbol weak 164 | if (cmd.OutputType == FILETYPE_COFF) { 165 | // PE/COFF format does not support weak publics. Use this only when converting to ELF 166 | err.submit(2200); 167 | } 168 | // Make weak 169 | binding = STB_WEAK; 170 | sym.st_bind = binding; 171 | sym.st_type = type ; 172 | break; 173 | 174 | case SYMA_MAKE_LOCAL: 175 | // Make public symbol local, make external symbol ignored 176 | binding = STB_LOCAL; SymbolType = SYMT_LOCAL; 177 | sym.st_bind = binding; 178 | sym.st_type = type ; 179 | break; 180 | 181 | case SYMA_CHANGE_NAME: 182 | // Change name of symbol 183 | name1 = name2; name2 = 0; 184 | break; 185 | 186 | case SYMA_CHANGE_ALIAS: 187 | // Make alias and keep old name 188 | if (isymt != 0) err.submit(1033, name1); // alias in dynsym not supported yet 189 | AliasEntry = sym; 190 | break; 191 | 192 | default: 193 | err.submit(9000); // unknown error 194 | } 195 | 196 | // Add entry to new string table 197 | if (name1 && *name1) { 198 | symnamei = NewStringTable[isymt].PushString(name1); 199 | } 200 | else { 201 | symnamei = 0; 202 | } 203 | sym.st_name = symnamei; 204 | 205 | if (isymt == 0) { 206 | // The symtab symbol table must be ordered with local symbols first. 207 | // Therefore the public and external symbols are temporarily stored 208 | // in TempGlobalSymbolTable and the high bit of NewSymi is set. 209 | // The two tables are joined together when the number of local symbols 210 | // is known and the indexes into TempGlobalSymbolTable are adjusted 211 | // to indexes into the joined table. 212 | if (SymbolType == SYMT_LOCAL) { 213 | NewSymbolTable[isymt].Push(&sym, entrysize); 214 | NewSymi = NewSymbolTable[isymt].GetLastIndex(); 215 | } 216 | else { 217 | TempGlobalSymbolTable.Push(&sym, entrysize); 218 | NewSymi = TempGlobalSymbolTable.GetLastIndex() | 0x80000000; 219 | } 220 | // Insert into symbol index translation table 221 | NewSymbolIndex[OldSymi] = NewSymi; 222 | 223 | if (action == SYMA_CHANGE_ALIAS && name2 && *name2) { 224 | // Make one more entry for new alias 225 | symnamei = NewStringTable[isymt].PushString(name2); 226 | AliasEntry.st_name = symnamei; 227 | TempGlobalSymbolTable.Push(&AliasEntry, entrysize); 228 | } 229 | } 230 | else { 231 | // dynsym table has no local symbols 232 | // no index translation table is currently needed 233 | NewSymbolTable[isymt].Push(&sym, entrysize); 234 | } 235 | 236 | } // End of loop through old symbol table 237 | 238 | if (isymt == 0) { 239 | // The symbol table has been temporarily split into local and non-local 240 | // Save index to first nonlocal symbol 241 | FirstGlobalSymbol = NewSymbolTable[isymt].GetNumEntries(); 242 | 243 | // Adjust symbol index translation table 244 | for (OldSymi = 0; OldSymi < NumOldSymbols; OldSymi++) { 245 | if (NewSymbolIndex[OldSymi] & 0x80000000) { 246 | // Translate index into TempGlobalSymbolTable to index into joined table 247 | NewSymbolIndex[OldSymi] = (NewSymbolIndex[OldSymi] & ~0x80000000) + FirstGlobalSymbol; 248 | } 249 | } 250 | 251 | // Join the two tables 252 | NewSymbolTable[isymt].Push(TempGlobalSymbolTable.Buf(), TempGlobalSymbolTable.GetDataSize()); 253 | } 254 | } 255 | } // End of isymt loop through possibly two symbol tables 256 | } 257 | 258 | 259 | // ChangeSections() 260 | template 261 | void CELF2ELF::ChangeSections() { 262 | // Convert subfunction: Change section names if needed and adjust all relocation tables 263 | uint32 SectionNumber; // Section number 264 | const char * name1; // Section name 265 | const char * name2; // Changed section name 266 | int action; // Name change action 267 | TELF_SectionHeader * sheaderp; // Pointer to section header 268 | uint32 SectionHeaderOffset; // File offset to section header 269 | uint32 namei; // Section name index into string table 270 | TELF_Relocation * relocp; // Pointer to relocation entry 271 | uint32 oldsymi, newsymi; // Relocation symbol index 272 | 273 | // Initialize section header string table .shstrtab. First entry = 0 274 | NewStringTable[2].Push(0, 1); 275 | 276 | // Loop through sections 277 | SectionHeaderOffset = uint32(this->FileHeader.e_shoff); 278 | for (SectionNumber = 0; SectionNumber < this->NSections; SectionNumber++, SectionHeaderOffset += this->FileHeader.e_shentsize) { 279 | 280 | // Get section header 281 | sheaderp = (TELF_SectionHeader*)(this->Buf() + SectionHeaderOffset); 282 | 283 | // Section name 284 | namei = sheaderp->sh_name; 285 | if (namei >= this->SecStringTableLen) err.submit(2112); 286 | name1 = this->SecStringTable + namei; 287 | 288 | // Check if name change 289 | action = cmd.SymbolChange(name1, &name2, SYMT_SECTION); 290 | if (action == SYMA_CHANGE_NAME) name1 = name2; 291 | 292 | // Store name in .shstrtab string table 293 | if (name1 && *name1) { 294 | namei = NewStringTable[2].PushString(name1); 295 | } 296 | else { 297 | namei = 0; 298 | } 299 | sheaderp->sh_name = namei; // Put new string index into section header 300 | 301 | if (sheaderp->sh_type == SHT_REL || sheaderp->sh_type == SHT_RELA) { 302 | // This is a relocation section. Update all symbol indices 303 | 304 | int8 * reltab = this->Buf() + sheaderp->sh_offset; 305 | int8 * reltabend = reltab + sheaderp->sh_size; 306 | int entrysize = (int)(sheaderp->sh_entsize); 307 | if (entrysize <= 0) entrysize = sizeof(TELF_Relocation); 308 | 309 | // Loop through entries 310 | for (; reltab < reltabend; reltab += entrysize) { 311 | relocp = (TELF_Relocation*)reltab; 312 | 313 | oldsymi = relocp->r_sym; 314 | 315 | if (oldsymi >= NumOldSymbols) { 316 | err.submit(2040); oldsymi = 0; 317 | } 318 | // Translate symbol index 319 | newsymi = NewSymbolIndex[oldsymi]; 320 | 321 | // Put back into relocation entry 322 | relocp->r_sym = newsymi; 323 | } 324 | } 325 | } 326 | } 327 | 328 | 329 | // MakeBinaryFile() 330 | template 331 | void CELF2ELF::MakeBinaryFile() { 332 | 333 | uint32 SectionNumber; // Section number 334 | CMemoryBuffer NewSectionHeaders; // Temporary storage of section headers 335 | 336 | // Copy file header 337 | ToFile.Push(this->Buf(), sizeof(TELF_Header)); 338 | 339 | // Copy program header if any 340 | if (this->FileHeader.e_phnum) { 341 | ToFile.Push(this->Buf() + this->FileHeader.e_phoff, this->FileHeader.e_phentsize * this->FileHeader.e_phnum); 342 | ((TELF_Header*)ToFile.Buf())->e_phoff = sizeof(TELF_Header); 343 | } 344 | 345 | // Copy section data 346 | uint32 SectionHeaderOffset = uint32(this->FileHeader.e_shoff); 347 | TELF_SectionHeader sheader; // Section header 348 | 349 | // Loop through sections 350 | for (SectionNumber = 0; SectionNumber < this->NSections; SectionNumber++, SectionHeaderOffset += this->FileHeader.e_shentsize) { 351 | 352 | // Get section header 353 | //sheader = this->Get(SectionHeaderOffset); 354 | // Some compilers fail with the double template here. Avoid the template: 355 | sheader = *(TELF_SectionHeader*)(this->Buf() + SectionHeaderOffset); 356 | 357 | // Check for null section 358 | if (SectionNumber == 0 && sheader.sh_type != 0) { 359 | // First section must be null 360 | err.submit(2036, 0); 361 | } 362 | 363 | // Align 364 | ToFile.Align(16); 365 | 366 | // Check for sections that have been modified 367 | if (SectionNumber == isymtab[0]) { 368 | // Static symbol table .symtab 369 | sheader.sh_offset = ToFile.Push(NewSymbolTable[0].Buf(), NewSymbolTable[0].GetDataSize()); 370 | sheader.sh_size = NewSymbolTable[0].GetDataSize(); 371 | sheader.sh_info = FirstGlobalSymbol; 372 | } 373 | else if (SectionNumber == isymtab[1]) { 374 | // Dynamic symbol table .dynsym 375 | sheader.sh_offset = ToFile.Push(NewSymbolTable[1].Buf(), NewSymbolTable[1].GetDataSize()); 376 | sheader.sh_size = NewSymbolTable[1].GetDataSize(); 377 | } 378 | else if (SectionNumber == istrtab[0]) { 379 | // Symbol string table .strtab 380 | sheader.sh_offset = ToFile.Push(NewStringTable[0].Buf(), NewStringTable[0].GetDataSize()); 381 | sheader.sh_size = NewStringTable[0].GetDataSize(); 382 | } 383 | else if (SectionNumber == istrtab[1] && SectionNumber != istrtab[0]) { 384 | // Dynamic symbol string table if different from .strtab 385 | sheader.sh_offset = ToFile.Push(NewStringTable[1].Buf(), NewStringTable[1].GetDataSize()); 386 | sheader.sh_size = NewStringTable[1].GetDataSize(); 387 | } 388 | else if (SectionNumber == istrtab[2]) { 389 | // Section name string table .shstrtab 390 | sheader.sh_offset = ToFile.Push(NewStringTable[2].Buf(), NewStringTable[2].GetDataSize()); 391 | sheader.sh_size = NewStringTable[2].GetDataSize(); 392 | } 393 | else { 394 | // Any other section (including istrtab[3] = .stabstr) 395 | sheader.sh_offset = ToFile.Push(this->Buf() + (uint32)sheader.sh_offset, (uint32)sheader.sh_size); 396 | } 397 | 398 | // Store section header 399 | NewSectionHeaders.Push(&sheader, sizeof(sheader)); 400 | 401 | } // End of section loop 402 | 403 | // Align 404 | ToFile.Align(16); 405 | 406 | // Store section headers 407 | uint32 SectionHeadersOffset = ToFile.Push(NewSectionHeaders.Buf(), NewSectionHeaders.GetDataSize()); 408 | 409 | // Update file header 410 | ((TELF_Header*)ToFile.Buf())->e_shoff = SectionHeadersOffset; 411 | ((TELF_Header*)ToFile.Buf())->e_shentsize = sizeof(TELF_SectionHeader); 412 | ((TELF_Header*)ToFile.Buf())->e_shnum = NewSectionHeaders.GetNumEntries(); 413 | ((TELF_Header*)ToFile.Buf())->e_shstrndx = istrtab[2]; 414 | } 415 | 416 | 417 | // Make template instances for 32 and 64 bits 418 | template class CELF2ELF; 419 | template class CELF2ELF; 420 | -------------------------------------------------------------------------------- /src/omfhash.cpp: -------------------------------------------------------------------------------- 1 | /**************************** omfhash.cpp ********************************** 2 | * Author: Agner Fog 3 | * Date created: 2007-02-14 4 | * Last modified: 2007-02-14 5 | * Project: objconv 6 | * Module: omfhash.cpp 7 | * Description: 8 | * This module contains code for searching and making hash tables for OMF 9 | * libraries. 10 | * 11 | * Copyright 2007-2008 GNU General Public License http://www.gnu.org/licenses 12 | *****************************************************************************/ 13 | 14 | #include "stdafx.h" 15 | 16 | void COMFHashTable::Init(SOMFHashBlock * blocks, uint32 NumBlocks) { 17 | // Initialize 18 | this->blocks = blocks; // Pointer to blocks 19 | this->NumBlocks = NumBlocks; // Number of blocks 20 | String = 0; 21 | StringLength = 0; 22 | } 23 | 24 | // Rotate right 16-bit word 25 | uint16 RotR(uint16 x, uint16 bits) { 26 | return (x >> bits) | (x << (16 - bits)); 27 | } 28 | 29 | // Rotate left 16-bit word 30 | uint16 RotL(uint16 x, uint16 bits) { 31 | return (x << bits) | (x >> (16 - bits)); 32 | } 33 | 34 | void COMFHashTable::MakeHash(int8 * name) { 35 | // Compute hash according to the official algorithm 36 | uint8 * pb; // Pointer for forward scan through string 37 | uint8 * pe; // Pointer for backwards scan through string 38 | uint16 c; // Current character converted to lower case 39 | uint16 BlockX; // Calculate block hash 40 | uint16 BucketX; // Calculate block hash 41 | String = (uint8*)name; // Type cast string to unsigned char * 42 | StringLength = (uint32)strlen(name); 43 | if (StringLength > 255) { 44 | // String too long 45 | err.submit(1204, name); // Warning: truncating 46 | StringLength = 255; 47 | String[StringLength] = 0; // Truncation modifies string source! 48 | } 49 | String = (uint8*)name; // Type cast to unsigned characters 50 | pb = String; // Initialize pointer for forward scan 51 | pe = String + StringLength; // Initialize pointer for backward scan 52 | BlockX = BucketD = StringLength | 0x20; // Initialize left-to-right scan 53 | BucketX = BlockD = 0; // Initialize right-to-left scan 54 | 55 | // Scan loop 56 | while (1) { 57 | c = *(--pe) | 0x20; // Read character for backward scan, make lower case 58 | BucketX = RotR(BucketX, 2) ^ c; // Rotate, XOR 59 | BlockD = RotL(BlockD, 2) ^ c; // Rotate, XOR 60 | if (pe == String) break; // Stop loop when backward scan finished 61 | c = *(pb++) | 0x20; // Read character for forward scan, make lower case 62 | BlockX = RotL(BlockX, 2) ^ c; // Rotate, XOR 63 | BucketD = RotR(BucketD, 2) ^ c; // Rotate, XOR 64 | } 65 | // Make values modulo number of blocks / buckets 66 | BlockX = BlockX % NumBlocks; 67 | BlockD = BlockD % NumBlocks; 68 | if (BlockD == 0) BlockD = 1; 69 | BucketX = BucketX % OMFNumBuckets; 70 | BucketD = BucketD % OMFNumBuckets; 71 | if (BucketD == 0) BucketD = 1; 72 | StartBlock = BlockX; 73 | StartBucket = BucketX; 74 | } 75 | 76 | 77 | int COMFHashTable::FindString(uint32 & ModulePage, uint32 & Conflicts) { 78 | // Search for String. 79 | // Returns number of occurrences of String 80 | // Module receives the module page for the first occurrence 81 | // Conflicts receives the number of conflicting entries encountered before the match 82 | uint32 Num = 0; // Number of occurrences of string found 83 | uint16 Block; // Block number 84 | uint16 Bucket; // Bucket number 85 | uint32 StringIndex; // Index to string 86 | Conflicts = 0; // Start counting Conflicts 87 | 88 | Block = StartBlock; 89 | Bucket = StartBucket; 90 | 91 | // Loop through blocks 92 | do { 93 | 94 | // Loop through buckets 95 | do { 96 | 97 | // String index of current bucket 98 | StringIndex = blocks[Block].b.Buckets[Bucket]; 99 | if (StringIndex == 0) { 100 | if (blocks[Block].b.FreeSpace < 0xff) { 101 | // Empty bucket found. End of search 102 | return Num; 103 | } 104 | else { 105 | // Block is full. Search next block 106 | 107 | // Note: It would be logical to set StartBucket = Bucket 108 | // here in order to allow all buckets in the next block 109 | // to be tried, but the official algorithm doesn't seem 110 | // to do so!? 111 | // StartBucket = Bucket; 112 | 113 | break; 114 | } 115 | } 116 | // Bucket contains a string. Is it the same string? 117 | if (blocks[Block].Strings[StringIndex*2] == StringLength 118 | && strncmp((int8*)&blocks[Block].Strings[StringIndex*2+1], (int8*)String, StringLength) == 0) { 119 | // Matching string found 120 | Num++; 121 | if (Num == 1) { 122 | // First occurrence. Save module number 123 | ModulePage = *(uint16*)&blocks[Block].Strings[StringIndex*2+1+StringLength]; 124 | } 125 | } 126 | else { 127 | // Conflicting string found 128 | Conflicts++; 129 | } 130 | // Next bucket 131 | Bucket = (Bucket + BucketD) % OMFNumBuckets; 132 | } while (Bucket != StartBucket); 133 | 134 | // Next block 135 | Block = (Block + BlockD) % NumBlocks; 136 | } while (Block != StartBlock); 137 | // Finished searching all blocks and buckets 138 | return Num; 139 | } 140 | 141 | int COMFHashTable::InsertString(uint16 & ModulePage) { 142 | // Insert string in hash table. 143 | // Parameter: 144 | // ModulePage = module address / page size 145 | // Return value: 146 | // 0 if success, 147 | // 1 if identical string allready exists in the table. New string will not be entered. 148 | // ModulePage will receive the module page of the existing string in this case. 149 | // 2 if table is full, 150 | uint16 Block; // Block number 151 | uint16 Bucket; // Bucket number 152 | uint32 StringIndex; // Index to string space 153 | uint32 StringOffset; // Offset to string from begin of block 154 | uint32 SpaceRequired; // Space required to store string 155 | 156 | SpaceRequired = StringLength + 3; // Space for string + stringlength + module index 157 | SpaceRequired = (SpaceRequired + 1) & uint32(-2);// Round up to nearest even 158 | 159 | Block = StartBlock; 160 | Bucket = StartBucket; 161 | 162 | // Loop through blocks 163 | do { 164 | 165 | // Loop through buckets 166 | do { 167 | 168 | // String index of current bucket 169 | StringIndex = blocks[Block].b.Buckets[Bucket]; 170 | if (StringIndex == 0) { 171 | // Found empty bucket. Check if block has enough free space 172 | if (uint32(OMFBlockSize) - blocks[Block].b.FreeSpace * 2 < SpaceRequired) { 173 | // Not enough space in block. 174 | // Continue with same bucket in next block. 175 | 176 | // Note: It would be logical to set StartBucket = Bucket 177 | // here in order to allow all buckets in the next block 178 | // to be tried, but the official algorithm doesn't seem 179 | // to do so!? 180 | // StartBucket = Bucket; 181 | break; 182 | } 183 | // Enough space found. Enter string in bucket 184 | StringIndex = blocks[Block].b.FreeSpace; 185 | blocks[Block].b.Buckets[Bucket] = StringIndex; 186 | // Address to store string 187 | StringOffset = StringIndex * 2; 188 | // Store string length 189 | blocks[Block].Strings[StringOffset] = (uint8)StringLength; 190 | // Copy string 191 | memcpy(blocks[Block].Strings + StringOffset + 1, String, StringLength); 192 | // Insert module page number 193 | *(uint16*)(blocks[Block].Strings + StringOffset + 1 + StringLength) = ModulePage; 194 | // Update free space 195 | blocks[Block].b.FreeSpace += (uint8)(SpaceRequired / 2); 196 | // Check if overflow 197 | if (blocks[Block].b.FreeSpace == 0) blocks[Block].b.FreeSpace = 0xFF; 198 | // Indicate success 199 | return 0; 200 | } 201 | else { 202 | // Bucket contains a string. Check if it is the same string 203 | if (blocks[Block].Strings[StringIndex*2] == StringLength 204 | && strncmp((int8*)(blocks[Block].Strings+StringIndex*2+1), (int8*)String, StringLength) == 0) { 205 | // Identical string found. Return module index for existing string entry 206 | ModulePage = *(uint16*)(blocks[Block].Strings+StringIndex*2+1+StringLength); 207 | // Indicate failure 208 | return 1; 209 | } 210 | } 211 | // Bucket was full. Go to next bucket 212 | Bucket = (Bucket + BucketD) % OMFNumBuckets; 213 | } while (Bucket != StartBucket); 214 | 215 | // If we got here, we have found no empty bucket in the block or 216 | // there was not enough string space in the block. 217 | // We need to mark the block as full to tell the linker to 218 | // continue in next block when searching for this string 219 | // Whether the block has any empty buckets or not 220 | blocks[Block].b.FreeSpace = 0xFF; 221 | 222 | // Go to next block 223 | Block = (Block + BlockD) % NumBlocks; 224 | } while (Block != StartBlock); 225 | 226 | // Finished searching all blocks and buckets 227 | // No empty space found. Indicate failure: 228 | return 2; 229 | } 230 | 231 | 232 | // Table of prime numbers 233 | // You may add more prime numbers if very big library files are needed 234 | static const uint32 PrimeNumbers[] = { 235 | 1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 236 | 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 237 | 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 238 | 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 239 | 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 240 | 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 241 | 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 242 | 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 243 | 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 244 | 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 245 | 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 246 | 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 247 | 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 248 | 1277, 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 249 | 1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 250 | 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549, 251 | 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, 1613, 1619, 1621, 252 | 1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, 253 | 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847, 254 | 1861, 1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 255 | 1951, 1973, 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 256 | 2053, 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, 2131, 2137, 257 | 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, 2251, 258 | 2267, 2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 259 | 2351, 2357, 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 260 | 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, 261 | 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, 2671, 262 | 2677, 2683, 2687, 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, 263 | 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819, 2833, 2837, 2843, 264 | 2851, 2857, 2861, 2879, 2887, 2897, 2903, 2909, 2917, 2927, 2939, 2953, 2957, 265 | 2963, 2969, 2971, 2999, 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, 266 | 3079, 3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181, 3187, 3191, 267 | 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271, 3299, 3301, 3307, 268 | 3313, 3319, 3323, 3329, 3331, 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, 269 | 3407, 3413, 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511, 3517, 270 | 3527, 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607, 271 | 3613, 3617, 3623, 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691, 3697, 3701, 272 | 3709, 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821, 273 | 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917, 3919, 274 | 3923, 3929, 3931, 3943, 3947, 3967, 3989, 4001, 4003, 4007, 4013, 4019, 4021, 275 | 4027, 4049, 4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, 276 | 4139, 4153, 4157, 4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, 277 | 4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297, 4327, 4337, 4339, 4349, 4357, 278 | 4363, 4373, 4391, 4397, 4409, 4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481, 279 | 4483, 4493, 4507, 4513, 4517, 4519, 4523, 4547, 4549, 4561, 4567, 4583, 4591, 280 | 4597, 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657, 4663, 4673, 4679, 4691, 281 | 4703, 4721, 4723, 4729, 4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799, 4801, 282 | 4813, 4817, 4831, 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937, 283 | 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, 5009, 5011, 5021 284 | }; 285 | 286 | // Length of table 287 | static const uint32 PrimeNumbersLen = sizeof(PrimeNumbers)/sizeof(PrimeNumbers[0]); 288 | 289 | 290 | void COMFHashTable::MakeHashTable(CSList & StringEntries, 291 | CMemoryBuffer & StringBuffer, CMemoryBuffer & OutFile, CLibrary * Library) { 292 | // Make hash table. Parameters: 293 | // StringEntries[].String = name of each public symbol as offset into StringBuffer 294 | // StringEntries[].Member = page address of member = offset / page size 295 | // StringBuffer = contains all strings 296 | // OutFile will receive the output hash table 297 | 298 | CSList HashTable; // Hash table 299 | COMFHashTable TableHandler; // Hash table handler 300 | uint32 NumBlocksI; // Number of blocks as index into prime number table 301 | uint32 BlockI; // Block index 302 | uint32 SymI; // Symbol index 303 | int8 * String; // Symbol name 304 | uint16 Module1, Module2; // Module page = offset / page size 305 | int Result; // 0 = success 306 | 307 | // Estimate required number of blocks 308 | NumBlocks = (StringEntries.GetNumEntries() * 8 + StringBuffer.GetDataSize()) / 256; 309 | // Find nearest prime number >= NumBlocks, but stay within the range from 2 to 251. 310 | // The minimum NumBlocks is 1, but some systems use 2 as the minimum. 311 | // The maximum is 251, but some linkers may allow a higher number 312 | 313 | for (NumBlocksI = 1; NumBlocksI < 55; NumBlocksI++) { 314 | if (PrimeNumbers[NumBlocksI] >= NumBlocks) break; 315 | } 316 | 317 | // Try if this number of blocks is sufficient 318 | while (NumBlocksI < PrimeNumbersLen) { 319 | 320 | // Get number of blocks from prime numbers table 321 | NumBlocks = PrimeNumbers[NumBlocksI]; 322 | 323 | // Check if <= 251 324 | if (NumBlocks > 255) err.submit(1215); // Number of blocks exceeds official limit. May still work with some linkers 325 | 326 | // Allocate space for hash table 327 | HashTable.SetNum(NumBlocks); 328 | memset(&HashTable[0], 0, NumBlocks * OMFBlockSize); 329 | 330 | // Initialize hash table handler 331 | TableHandler.Init(&HashTable[0], NumBlocks); 332 | 333 | // Set free space pointers 334 | for (BlockI = 0; BlockI < NumBlocks; BlockI++) { 335 | TableHandler.blocks[BlockI].b.FreeSpace = 19; 336 | } 337 | Result = 0; 338 | 339 | // Insert symbols 340 | // Loop through symbols 341 | for (SymI = 0; SymI < StringEntries.GetNumEntries(); SymI++) { 342 | 343 | // Symbol name 344 | String = StringBuffer.Buf() + StringEntries[SymI].String; 345 | 346 | // Module page 347 | Module1 = Module2 = StringEntries[SymI].Member; 348 | 349 | // Insert name in table 350 | TableHandler.MakeHash(String); 351 | Result = TableHandler.InsertString(Module2); 352 | 353 | if (Result == 1) { 354 | // String already exists 355 | // Compose error string "Modulename1 and Modulename2" 356 | char ErrorModuleNames[64]; 357 | strcpy(ErrorModuleNames, Library->GetModuleName(Module1)); 358 | strcpy(ErrorModuleNames + strlen(ErrorModuleNames), " and "); 359 | strcpy(ErrorModuleNames + strlen(ErrorModuleNames), Library->GetModuleName(Module2)); 360 | // submit error message 361 | err.submit(1214, String, ErrorModuleNames); 362 | } 363 | if (Result == 2) { 364 | // Table is full. Stop and repeat with a higher NumBlocks 365 | break; 366 | } 367 | } // End of loop through symbols 368 | 369 | if (Result < 2) { 370 | // Finished with success 371 | // Store hash table 372 | OutFile.Push(&HashTable[0], HashTable.GetNumEntries() * OMFBlockSize); 373 | return; 374 | } 375 | 376 | // Table is full. Try again with a higher number of blocks 377 | NumBlocksI++; 378 | } 379 | 380 | // End of loop through PrimeNumbers table 381 | err.submit(2605); // Failed to make table 382 | } 383 | -------------------------------------------------------------------------------- /src/containers.h: -------------------------------------------------------------------------------- 1 | /**************************** containers.h ******************************** 2 | * Author: Agner Fog 3 | * Date created: 2006-07-15 4 | * Last modified: 2007-02-01 5 | * Project: objconv 6 | * Module: containers.h 7 | * Description: 8 | * Header file for container classes and dynamic memory allocation 9 | * 10 | * Copyright 2006-2008 GNU General Public License http://www.gnu.org/licenses 11 | *****************************************************************************/ 12 | 13 | /***************************************************************************** 14 | This header file declares various container classes for dynamic allocation 15 | of memory for files and other types of data with unpredictable sizes. 16 | These classes have private access to the memory buffer in order to prevent 17 | memory leaks. It is important to use these classes for all dynamic memory 18 | allocation. 19 | 20 | The class CMemoryBuffer and its descendants are used for many purposes of 21 | storage of data with a size that is not known in advance. CMemoryBuffer 22 | allows the size of its data to grow when new data are appended with the 23 | Push() member function. 24 | 25 | The class CFileBuffer, which is derived from CMemoryBuffer, is used for 26 | reading, writing and storing object files and other files. 27 | 28 | There are many different classes for different things you can do with 29 | an object file. These classes, declared in converters.h, are all 30 | descendants of CFileBuffer. It is possible to transfer a data buffer 31 | from one object to another by the operator 32 | 33 | A >> B 34 | 35 | where A and B are both objects of classes that descend from CFileBuffer. 36 | The file buffer that was owned by A is transferred to B and A is left empty 37 | after the A >> B operation. This makes sure that a memory buffer is always 38 | owned by one, and only one, object. The opposite operator B << A does the 39 | same thing. 40 | 41 | The >> operator is used whenever we want to do something to a file buffer 42 | that requires a specialized class. The file buffer is transferred from the 43 | object that owns it to an object of the specialized class and transferred 44 | back again to the original owner when the object of the specialized class 45 | has done its job. 46 | 47 | You may say that the descendants of CFileBuffer have a chameleonic nature: 48 | You can change the nature of a piece of data owned by an object by 49 | transferring it to an object of a different class. This couldn't be done 50 | by traditional polymorphism because it is not possible to change the class 51 | of an object after it is created, and there are too many different things 52 | you can do with object files for a single class to handle them all. 53 | 54 | The container class CMemoryBuffer is useful for storing data of mixed types. 55 | Data of arbitrary type can be accessed by Get(offset) or by 56 | Buf() + offset. 57 | 58 | If all items in a dynamic array are of the same type then it is easier to 59 | use one of the template classes CArrayBuf<> or CSList<>. These can be 60 | used in the same way as normal arrays with the operator []. 61 | CArrayBuf<> and CSList<> both have a member function SetNum() to allocate 62 | the size. The size of CArrayBuf<> can be set only once, while the size of 63 | CSList<> can be changed at any time. CSList<> also has a member function 64 | Push() that adds records sequentially. CSList can be sorted if operators 65 | < and == are defined for the record type. 66 | 67 | Warning: 68 | It is necessary to use CArrayBuf<> rather than CSList<> if the record type 69 | has a constructor or destructor. 70 | 71 | Warning: 72 | It is not safe to make pointers to data inside a dynamic array of type 73 | CMemoryBuffer or CSList<> because the buffer may be re-allocated when the 74 | size grows. Such pointers will only work if we are finished with all push 75 | operations. It is safer to address data inside the buffer by their index 76 | or offset relative to the buffer. 77 | 78 | *****************************************************************************/ 79 | 80 | #ifndef CONTAINERS_H 81 | #define CONTAINERS_H 82 | 83 | extern CErrorReporter err; // Defined in error.cpp 84 | 85 | class CFileBuffer; // Declared below 86 | 87 | void operator >> (CFileBuffer & a, CFileBuffer & b); // Transfer ownership of buffer and other properties 88 | 89 | // Class CMemoryBuffer makes a dynamic array which can grow as new data are 90 | // added. Used for storage of files, file sections, tables, etc. 91 | class CMemoryBuffer { 92 | public: 93 | CMemoryBuffer(); // Constructor 94 | ~CMemoryBuffer(); // Destructor 95 | void SetSize(uint32 size); // Allocate buffer of specified size 96 | uint32 GetDataSize() {return DataSize;}; // File data size 97 | uint32 GetBufferSize(){return BufferSize;}; // Buffer size 98 | uint32 GetNumEntries(){return NumEntries;}; // Get number of entries 99 | uint32 Push(void const * obj, uint32 size); // Add object to buffer, return offset 100 | uint32 PushString(char const * s); // Add ASCIIZ string to buffer, return offset 101 | uint32 GetLastIndex(); // Index of last object pushed (zero-based) 102 | void Align(uint32 a); // Align next entry to address divisible by a 103 | int8 * Buf() {return buffer;}; // Access to buffer 104 | template TX & Get(uint32 Offset) { // Get object of arbitrary type from buffer 105 | if (Offset >= DataSize) {err.submit(2016); Offset = 0;} // Offset out of range 106 | return *(TX*)(buffer + Offset);} 107 | private: 108 | CMemoryBuffer(CMemoryBuffer&); // Make private copy constructor to prevent copying 109 | int8 * buffer; // Buffer containing binary data. To be modified only by SetSize and operator >> 110 | uint32 BufferSize; // Size of allocated buffer ( > DataSize) 111 | protected: 112 | uint32 NumEntries; // Number of objects pushed 113 | uint32 DataSize; // Size of data, offset to vacant space 114 | friend void operator >> (CFileBuffer & a, CFileBuffer & b); // Transfer ownership of buffer and other properties 115 | }; 116 | 117 | static inline void operator << (CFileBuffer & b, CFileBuffer & a) {a >> b;} // Same as operator << above 118 | 119 | 120 | // Class CFileBuffer is used for storage of input and output files 121 | class CFileBuffer : public CMemoryBuffer { 122 | public: 123 | CFileBuffer(); // Default constructor 124 | CFileBuffer(char const * filename); // Constructor 125 | void Read(int IgnoreError = 0); // Read file into buffer 126 | void Write(); // Write buffer to file 127 | int GetFileType(); // Get file format type 128 | void SetFileType(int type); // Set file format type 129 | void Reset(); // Set all members to zero 130 | static char const * GetFileFormatName(int FileType); // Get name of file format type 131 | char const * FileName; // Name of input file 132 | char const * OutputFileName; // Output file name 133 | int WordSize; // Segment word size (16, 32, 64) 134 | int FileType; // Object file type 135 | int Executable; // File is executable 136 | protected: 137 | void GetOMFWordSize(); // Determine word size for OMF file 138 | void CheckOutputFileName(); // Make output file name or check that requested name is valid 139 | }; 140 | 141 | 142 | // Class CTextFileBuffer is used for building text files 143 | class CTextFileBuffer : public CFileBuffer { 144 | public: 145 | CTextFileBuffer(); // Constructor 146 | void Put(const char * text); // Write text string to buffer 147 | void Put(const char character); // Write single character to buffer 148 | void NewLine(); // Add linefeed 149 | void Tabulate(uint32 i); // Insert spaces until column i 150 | int LineType; // 0 = DOS/Windows linefeeds, 1 = UNIX linefeeds 151 | void PutDecimal(int32 x, int IsSigned = 0); // Write decimal number to buffer 152 | void PutHex(uint8 x, int MasmForm = 0); // Write hexadecimal number to buffer 153 | void PutHex(uint16 x, int MasmForm = 0); // Write hexadecimal number to buffer 154 | void PutHex(uint32 x, int MasmForm = 0); // Write hexadecimal number to buffer 155 | void PutHex(uint64 x, int MasmForm = 0); // Write hexadecimal number to buffer 156 | void PutFloat(float x); // Write floating point number to buffer 157 | void PutFloat(double x); // Write floating point number to buffer 158 | uint32 GetColumn() {return column;} // Get column number 159 | protected: 160 | uint32 column; // Current column 161 | private: 162 | uint32 PushString(char const * s){return 0;}; // Make PushString private to prevent using it 163 | }; 164 | 165 | 166 | // Class CArrayBuf is used for dynamic arrays. 167 | // The size of the array can be set only once. 168 | // Use CArrayBuf rather than one of the other container classes if RecordType 169 | // has a constructor or destructor. 170 | template 171 | class CArrayBuf { 172 | private: 173 | RecordType * buffer; // Dynamically allocated memory 174 | uint32 num; // Number of entries in array 175 | CArrayBuf (CArrayBuf &); // Make private copy constructor to prevent copying 176 | public: 177 | CArrayBuf() { // Default constructor 178 | num = 0; 179 | } 180 | ~CArrayBuf() { // Destructor 181 | if (num) delete[] buffer; // Deallocate memory. Will call RecordType destructor if any 182 | } 183 | void SetNum(uint32 n) { // Set size of array. May be called only once! 184 | if (n <= num) return; // Already allocated 185 | if (num) { 186 | err.submit(9004); // Cannot resize because items may have destructors 187 | } 188 | else { 189 | buffer = new RecordType[n]; // Allocate memory. Will call RecordType constructor if any 190 | if (!buffer) { 191 | err.submit(9006); // Memory allocation failed 192 | } 193 | else { 194 | num = n; // Save size 195 | memset(buffer, 0, n*sizeof(RecordType));// Initialize to zero 196 | } 197 | } 198 | } 199 | uint32 GetNumEntries() { 200 | return num; // Read size 201 | } 202 | RecordType & operator[] (uint32 i) { // Access array element [i] 203 | if (i >= num) { 204 | err.submit(9003); i = 0; // Error: index out of range 205 | } 206 | return buffer[i]; 207 | } 208 | void SetZero() { // Set all items in array to 0 209 | memset(buffer, 0, num*sizeof(RecordType)); // Warning: overwrites all members of RecordType with 0 210 | } 211 | }; 212 | 213 | 214 | // Class CSList is used for dynamic arrays where all records 215 | // have the same type RecordType. The list can be sorted if desired. 216 | // 217 | // An array defined as 218 | // CSList list; 219 | // can be used in several ways: 220 | // 221 | // 1. The size can be set with list.SetNum(n) where n is the maximum number of 222 | // entries. New entries can then be added in random order with list[i] = x; 223 | // where i < n. Unused entries will be zero. 224 | // 2. Entries can be added sequentially with 225 | // list.Push(x); 226 | // The first entry will be list[0] 227 | // 3. Entries added with method 1 or 2 can be sorted in ascending order by 228 | // calling list.Sort(); 229 | // 4. The list can be kept sorted at all times if records are added with 230 | // list.PushSort(x); 231 | // The list will be kept sorted in ascending order, provided that it 232 | // was sorted before the call to PushSort. 233 | // 5. The list can be kept sorted at all times and without duplicates if 234 | // records are added with list.PushUnique(x); 235 | // The list will be sorted and without duplicates after PushUnique if 236 | // it was so before the call to PushUnique. 237 | // 6. Entries can be read at all times as x = list[i]; 238 | // An error will be submitted if i >= list.GetNumEntries() 239 | // 7. A sorted list can be searched for entry x by i = list.FindFirst(x); 240 | // or i = list.Exists(x); 241 | // 242 | // Requirements: 243 | // RecordType can be a simple type, a structure or a class. 244 | // If RecordType has a constructor or destructor then they will not be 245 | // called properly. Use CArrayBuf instead of CSList if RecordType has 246 | // a constructor or destructor. 247 | // The operator < const must be defined for RecordType if any of the sorting 248 | // features are used, i.e. Sort(), PushSort(), FindFirst(), Exists(). 249 | // 250 | // Example: 251 | // struct S1 { // Define RecordType 252 | // int Index; 253 | // int operator < (S1 const & x) const { // Define operator < 254 | // return Index < x.Index;} 255 | // }; 256 | // CSList list; // Make list 257 | // S1 a; a.Index = 5; // Make record 258 | // list.PushUnique(a); // Put record into list 259 | 260 | template 261 | class CSList : private CMemoryBuffer { 262 | public: 263 | void Push(RecordType const & x) { 264 | // Add member to list 265 | CMemoryBuffer::Push(&x, sizeof(x)); 266 | } 267 | void PushZero() { 268 | // Add blank entry to list 269 | CMemoryBuffer::Push(0, sizeof(RecordType)); 270 | } 271 | void SetNum(uint32 n) { 272 | // Reserve space for n entries. Fill with zeroes 273 | SetSize(n * sizeof(RecordType)); 274 | NumEntries = n; DataSize = n * sizeof(RecordType); 275 | } 276 | uint32 GetNumEntries() { 277 | // Get number of entries 278 | return NumEntries; 279 | } 280 | RecordType & operator[] (uint32 i) { 281 | // Get entries by operator [] as for an array 282 | if (i >= NumEntries) { 283 | err.submit(9003); i = 0;} // Error: index out of range 284 | return *(RecordType*)(Buf() + i * sizeof(RecordType)); 285 | } 286 | void Sort() { 287 | // Sort list by ascending RecordType items 288 | // Operator < must be defined for RecordType 289 | // Simple Bubble sort: 290 | int32 i, j; 291 | RecordType temp, * p1, * p2; 292 | for (i = 0; i < (int32)NumEntries; i++) { 293 | for (j = 0; j < (int32)NumEntries - i - 1; j++) { 294 | p1 = (RecordType*)(Buf() + j * sizeof(RecordType)); 295 | p2 = (RecordType*)(Buf() + (j+1) * sizeof(RecordType)); 296 | if (*p2 < *p1) { 297 | // Swap records 298 | temp = *p1; *p1 = *p2; *p2 = temp; 299 | } 300 | } 301 | } 302 | } 303 | int32 FindFirst(RecordType const & x) { 304 | // Returns index to first record >= x. 305 | // Returns 0 if x is smaller than all entries. 306 | // Returns NumEntries if x is bigger than all entries. Note that this 307 | // is not a valid index into the list. 308 | // List must be sorted before calling FindFirst 309 | uint32 a = 0; // Start of search interval 310 | uint32 b = NumEntries; // End of search interval + 1 311 | uint32 c = 0; // Middle of search interval 312 | // Binary search loop: 313 | while (a < b) { 314 | c = (a + b) / 2; 315 | if ((*this)[c] < x) { 316 | a = c + 1;} 317 | else { 318 | b = c;} 319 | } 320 | return (int32)a; 321 | } 322 | int32 Exists(RecordType const & x) { 323 | // Returns the record number if a record equal to x exists in the list. 324 | // Returns -1 if not. The list must be sorted before calling Exists. 325 | // Two records a and b are assumed to be equal if !(a < b || b < a) 326 | int32 i = FindFirst(x); 327 | if (i == NumEntries) return -1; 328 | if (x < (*this)[i]) return -1; else return i; 329 | } 330 | int32 PushSort(RecordType const & x) { 331 | // Add member to list and keep the list sorted. 332 | // If the list is sorted before calling PushSort then it will also be 333 | // sorted after the call. If x is equal to an existing entry then x 334 | // will be inserted before the existing entry. 335 | // Operator < must be defined for RecordType. 336 | int32 i = FindFirst(x); // Find where to insert x 337 | int32 RecordsToMove = (int32)NumEntries-i; // Number of records to move 338 | SetNum(NumEntries + 1); // Make space for one more record 339 | // Move subsequent entries up one place 340 | if (RecordsToMove > 0) { 341 | memmove(Buf() + i * sizeof(RecordType) + sizeof(RecordType), 342 | Buf() + i * sizeof(RecordType), 343 | RecordsToMove * sizeof(RecordType)); 344 | } 345 | // Insert x at position i 346 | (*this)[i] = x; 347 | return i; 348 | } 349 | int32 PushUnique(RecordType const & x) { 350 | // Add member to list and keep the list sorted. Avoids duplicate entries. 351 | // PushUnique will insert x in the list and keep the list sorted. 352 | // If an entry equal to x already exists in the list then x is not 353 | // inserted, and the return value will be the index to the existing entry. 354 | // If no entry equal to x existed then x is inserted and the return 355 | // value is the index to the new entry. 356 | // This list must be sorted and without duplicates before calling 357 | // PushUnique. 358 | // Operator < must be defined for RecordType. 359 | int32 i = FindFirst(x); // Find where to insert x 360 | if (i < (int32)NumEntries && !(x < (*this)[i])) { 361 | return i; // Duplicate found. Return index 362 | } 363 | int32 RecordsToMove = (int32)NumEntries-i; // Number of records to move 364 | SetNum(NumEntries + 1); // Make space for one more record 365 | // Move subsequent entries up one place 366 | if (RecordsToMove > 0) { 367 | memmove(Buf() + i * sizeof(RecordType) + sizeof(RecordType), 368 | Buf() + i * sizeof(RecordType), 369 | RecordsToMove * sizeof(RecordType)); 370 | } 371 | // Insert x at position i 372 | (*this)[i] = x; 373 | // Return index 374 | return i; 375 | } 376 | void Remove(uint32 index) { 377 | // Remove record with this index 378 | if (index >= NumEntries) return; // Index out of range 379 | uint32 RecordsToMove = NumEntries - index - 1; // Number of records to move 380 | // Move subsequent entries down one place 381 | if (RecordsToMove > 0) { 382 | memmove(Buf() + index * sizeof(RecordType), 383 | Buf() + index * sizeof(RecordType) + sizeof(RecordType), 384 | RecordsToMove * sizeof(RecordType)); 385 | } 386 | // Count down number of entries 387 | SetNum(NumEntries - 1); 388 | } 389 | }; 390 | 391 | #endif // #ifndef CONTAINERS_H 392 | -------------------------------------------------------------------------------- /src/elf2asm.cpp: -------------------------------------------------------------------------------- 1 | /**************************** elf2cof.cpp ********************************* 2 | * Author: Agner Fog 3 | * Date created: 2007-04-22 4 | * Last modified: 2011-08-22 5 | * Project: objconv 6 | * Module: elf2asm.cpp 7 | * Description: 8 | * Module for disassembling ELF 9 | * 10 | * Copyright 2007-2011 GNU General Public License http://www.gnu.org/licenses 11 | *****************************************************************************/ 12 | #include "stdafx.h" 13 | // All functions in this module are templated to make two versions: 32 and 64 bits. 14 | // See instantiations at the end of this file. 15 | 16 | 17 | // Constructor 18 | template 19 | CELF2ASM::CELF2ASM() { 20 | } 21 | 22 | 23 | // FindImageBase() 24 | template 25 | void CELF2ASM::FindImageBase() { 26 | // Find image base if executable file 27 | 28 | // Check if executable 29 | switch (this->FileHeader.e_type) { 30 | case ET_REL: default: 31 | // Not an executable file 32 | ExeType = 0; ImageBase = 0; 33 | return; 34 | case ET_DYN: // Shared object 35 | ExeType = 1; 36 | break; 37 | case ET_EXEC: // Executable file 38 | ExeType = 2; 39 | break; 40 | } 41 | 42 | // Loop through sections to find the first allocated section 43 | for (uint32 sc = 0; sc < this->NSections; sc++) { 44 | if (this->SectionHeaders[sc].sh_type == SHT_PROGBITS // Must be code or data section 45 | && (this->SectionHeaders[sc].sh_flags & SHF_ALLOC) // Must be allocated 46 | && this->SectionHeaders[sc].sh_offset <= this->SectionHeaders[sc].sh_addr) { // Avoid negative 47 | // Image base can be calculated from this section 48 | ImageBase = this->SectionHeaders[sc].sh_addr - this->SectionHeaders[sc].sh_offset; 49 | // Make sure ImageBase is divisible by page size 50 | ImageBase = ImageBase & - 0x1000; 51 | // Stop searching 52 | return; 53 | } 54 | } 55 | // Failure. Cannot compute image base from any of the sections 56 | ImageBase = 0; 57 | return; 58 | } 59 | 60 | 61 | // Convert 62 | template 63 | void CELF2ASM::Convert() { 64 | // Do the conversion 65 | 66 | // Find image base and executable type 67 | FindImageBase(); 68 | 69 | // Tell disassembler 70 | Disasm.Init(ExeType, ImageBase); // Set image base 71 | 72 | // Make Sections list in Disasm 73 | MakeSectionList(); 74 | 75 | // Make Symbols list in Disasm 76 | MakeSymbolList(); 77 | 78 | // Make relocations for object and executable files 79 | MakeRelocations(); 80 | 81 | if (ImageBase) { 82 | // Executable file 83 | MakeImportList(); // Make imported symbols for executable files 84 | MakeExportList(); // Make exported symbols for executable files 85 | MakeListLabels(); // Put labels on all image directory tables 86 | } 87 | Disasm.Go(); // Disassemble 88 | *this << Disasm.OutFile; // Take over output file from Disasm 89 | } 90 | 91 | // MakeSectionList 92 | template 93 | void CELF2ASM::MakeSectionList() { 94 | // Make Sections list and Relocations list in Disasm 95 | 96 | // Allocate array for translating oroginal section numbers to new index 97 | SectionNumberTranslate.SetNum(this->NSections + 1); 98 | uint32 NewSectionIndex = 0; 99 | 100 | for (uint32 sc = 0; sc < this->NSections; sc++) { 101 | // Get copy of 32-bit header or converted 64-bit header 102 | TELF_SectionHeader sheader = this->SectionHeaders[sc]; 103 | int entrysize = (uint32)(sheader.sh_entsize); 104 | uint32 namei = sheader.sh_name; 105 | if (namei >= this->SecStringTableLen) {err.submit(2112); break;} 106 | 107 | // if (sheader.sh_type == SHT_PROGBITS || sheader.sh_type == SHT_NOBITS) { 108 | // // This is a code, data or bss section 109 | 110 | if (sheader.sh_flags & SHF_ALLOC) { 111 | // This is an allocated section 112 | 113 | // Give it a new index 114 | SectionNumberTranslate[sc] = ++NewSectionIndex; 115 | 116 | // Get section parameters 117 | uint8 * Buffer = (uint8*)(this->Buf()) + (uint32)sheader.sh_offset; 118 | uint32 InitSize = (sheader.sh_type == SHT_NOBITS) ? 0 : (uint32)sheader.sh_size; 119 | uint32 TotalSize = (uint32)sheader.sh_size; 120 | uint32 SectionAddress = (uint32)sheader.sh_addr - (uint32)ImageBase; 121 | uint32 Align = FloorLog2((uint32)sheader.sh_addralign); 122 | const char * Name = this->SecStringTable + namei; 123 | 124 | // Detect segment type 125 | uint32 Type = 0; 126 | if (sheader.sh_flags & SHF_ALLOC) { 127 | // Allocate 128 | if (sheader.sh_type == SHT_NOBITS) { 129 | // Uninitialized data 130 | Type = 3; 131 | } 132 | else if (sheader.sh_flags & SHF_EXECINSTR) { 133 | // Executable 134 | Type = 1; 135 | } 136 | else if (!(sheader.sh_flags & SHF_WRITE)) { 137 | // Not writeable 138 | Type = 4; 139 | } 140 | else { 141 | // Initialized writeable data 142 | Type = 2; 143 | } 144 | } 145 | 146 | // Save section record 147 | Disasm.AddSection(Buffer, InitSize, TotalSize, SectionAddress, Type, Align, this->WordSize, Name); 148 | } 149 | } 150 | } 151 | 152 | // MakeSymbolList 153 | template 154 | void CELF2ASM::MakeSymbolList() { 155 | // Make Symbols list in Disasm 156 | 157 | // Allocate array for translate symbol indices for multiple symbol tables in 158 | // source file to a single symbol table in disassembler 159 | SymbolTableOffset.SetNum(this->NSections + 1); 160 | NumSymbols = 0; 161 | 162 | for (uint32 sc = 0; sc < this->NSections; sc++) { 163 | // Get copy of 32-bit header or converted 64-bit header 164 | TELF_SectionHeader sheader = this->SectionHeaders[sc]; 165 | int entrysize = (uint32)(sheader.sh_entsize); 166 | 167 | if (sheader.sh_type==SHT_SYMTAB || sheader.sh_type==SHT_DYNSYM) { 168 | // This is a symbol table 169 | 170 | // Offset for symbols in this symbol table = number of preceding symbols from other symbol tables 171 | SymbolTableOffset[sc] = NumSymbols; 172 | 173 | // Find associated string table 174 | if (sheader.sh_link >= this->NSections) {err.submit(2035); sheader.sh_link = 0;} 175 | int8 * strtab = this->Buf() + uint32(this->SectionHeaders[sheader.sh_link].sh_offset); 176 | 177 | // Find symbol table 178 | uint32 symtabsize = (uint32)(sheader.sh_size); 179 | int8 * symtab = this->Buf() + uint32(sheader.sh_offset); 180 | int8 * symtabend = symtab + symtabsize; 181 | if (entrysize < sizeof(TELF_Symbol)) {err.submit(2033); entrysize = sizeof(TELF_Symbol);} 182 | 183 | // Loop through symbol table 184 | uint32 symi1; // Symbol number in this table 185 | uint32 symi2; // Symbol number in joined table 186 | symtab += entrysize; // Skip symbol number 0 187 | for (symi1 = 1; symtab < symtabend; symtab += entrysize, symi1++) { 188 | 189 | // Symbol number in joined table = symi1 + number of symbols in preceding tables 190 | symi2 = SymbolTableOffset[sc] + symi1; 191 | 192 | // Copy 32 bit symbol table entry or convert 64 bit entry 193 | TELF_Symbol sym = *(TELF_Symbol*)symtab; 194 | 195 | // Parameters 196 | uint32 Offset = uint32(sym.st_value); 197 | uint32 Size = (uint32)sym.st_size; 198 | 199 | // Get section 200 | int32 Section = int16(sym.st_shndx); 201 | if (Section >= (int32)(this->NSections)) { 202 | // Error. wrong section 203 | Section = 0; 204 | } 205 | if (Section > 0) { 206 | // Translate to new section index 207 | Section = SectionNumberTranslate[Section]; 208 | } 209 | else if ((int16)Section < 0) { 210 | // Special section values 211 | if ((int16)Section == SHN_ABS) { 212 | // Absolute symbol 213 | Section = ASM_SEGMENT_ABSOLUTE; 214 | } 215 | else { 216 | // Other special values 217 | Section = ASM_SEGMENT_ERROR; 218 | } 219 | } 220 | 221 | // Get name 222 | const char * Name = 0; 223 | if (*(strtab + sym.st_name)) { 224 | Name = strtab + sym.st_name; 225 | } 226 | 227 | // Get import .so name 228 | const char * DLLName = 0; 229 | if (sheader.sh_type==SHT_DYNSYM && sym.st_value == 0 230 | && sym.st_shndx == 0 && sym.st_size > 0) { 231 | // I don't know how to find out which .so the symbol is imported from 232 | // It must be something in the .dynamic section. 233 | DLLName = "?.so"; 234 | } 235 | 236 | // Get scope 237 | uint32 Scope = 0; 238 | switch (sym.st_bind) { 239 | case STB_LOCAL: 240 | Scope = 2; 241 | break; 242 | case STB_WEAK: 243 | Scope = 8; 244 | if (Section > 0) break; 245 | // Section == 0: continue as global 246 | case STB_GLOBAL: 247 | // Public or external 248 | Scope = (sym.st_shndx > 0) ? 4 : 0x20; 249 | break; 250 | } 251 | // Get type 252 | uint32 Type = 0; 253 | 254 | if (sym.st_type == STT_FUNC) { 255 | // Function 256 | Type = 0x83; 257 | } 258 | else if (sym.st_type == STT_GNU_IFUNC) { 259 | // Gnu indirect function 260 | Type = 0x40000083; 261 | } 262 | else if (sym.st_type == STT_OBJECT) { 263 | // Probably a data object 264 | switch (Size) { 265 | case 1: 266 | Type = 1; 267 | break; 268 | case 2: 269 | Type = 2; 270 | break; 271 | case 4: 272 | Type = 3; 273 | break; 274 | case 8: 275 | Type = 4; 276 | break; 277 | default: 278 | Type = 1; 279 | break; 280 | } 281 | } 282 | else if (sym.st_type == STT_COMMON) { 283 | // Communal? 284 | Type = 0; 285 | Scope = 0x10; 286 | } 287 | else if (sym.st_type == STT_SECTION) { 288 | // This is a section 289 | Type = 0x80000082; 290 | Scope = 0; 291 | } 292 | else if (sym.st_type == STT_NOTYPE) { 293 | Type = 0; 294 | } 295 | else if (sym.st_type == STT_FILE) { 296 | // file name. ignore 297 | continue; 298 | } 299 | else { 300 | // unknown type. warning 301 | err.submit(1062, Name); 302 | Type = 0; 303 | //continue; 304 | } 305 | 306 | if (Scope != 0x20) { 307 | // Not external 308 | // Check if offset is absolute or section relative 309 | if (ExeType && Offset >= (uint32)ImageBase) { 310 | // Offset is absolute address 311 | if (Section >= 0 312 | && (uint32)Section < this->NSections 313 | && Offset >= (uint32)this->SectionHeaders[Section].sh_addr 314 | && Offset - (uint32)this->SectionHeaders[Section].sh_addr < (uint32)(this->SectionHeaders[Section].sh_size)) { 315 | // Change to section relative offset 316 | Offset -= (uint32)(this->SectionHeaders[Section].sh_addr); 317 | } 318 | else { 319 | // Address is outside specified section or otherwise inconsistent. 320 | // Let Disasm try to find the address 321 | Section = ASM_SEGMENT_IMGREL; 322 | Offset -= (uint32)ImageBase; 323 | } 324 | } 325 | } 326 | 327 | // Store new symbol record 328 | Disasm.AddSymbol(Section, Offset, Size, Type, Scope, symi2, Name, DLLName); 329 | 330 | // Count symbols 331 | NumSymbols++; 332 | } 333 | } 334 | } 335 | } 336 | 337 | // MakeRelocations 338 | template 339 | void CELF2ASM::MakeRelocations() { 340 | // Make relocations for object and executable files 341 | 342 | int32 Section; // Source section new index 343 | 344 | // Loop through sections 345 | for (uint32 sc = 0; sc < this->NSections; sc++) { 346 | // Get copy of 32-bit header or converted 64-bit header 347 | TELF_SectionHeader sheader = this->SectionHeaders[sc]; 348 | int entrysize = (uint32)(sheader.sh_entsize); 349 | 350 | if (sheader.sh_type == SHT_REL || sheader.sh_type == SHT_RELA) { 351 | // Relocations section 352 | int8 * reltab = this->Buf() + uint32(sheader.sh_offset); 353 | int8 * reltabend = reltab + uint32(sheader.sh_size); 354 | int expectedentrysize = sheader.sh_type == SHT_RELA ? 355 | sizeof(TELF_Relocation) : // Elf32_Rela, Elf64_Rela 356 | sizeof(TELF_Relocation) - this->WordSize/8; // Elf32_Rel, Elf64_Rel 357 | if (entrysize < expectedentrysize) {err.submit(2033); entrysize = expectedentrysize;} 358 | 359 | // Loop through entries 360 | for (; reltab < reltabend; reltab += entrysize) { 361 | // Copy relocation table entry with or without addend 362 | TELF_Relocation rel; rel.r_addend = 0; 363 | memcpy(&rel, reltab, entrysize); 364 | 365 | // Get section-relative or absolute address 366 | uint32 Offset = (uint32)rel.r_offset; 367 | 368 | // Get addend, if any 369 | int32 Addend = (uint32)rel.r_addend; 370 | 371 | // Find target symbol 372 | uint32 TargetIndex = rel.r_sym; 373 | if (sheader.sh_link < this->NSections) { 374 | // sh_link indicates which symbol table r_sym refers to 375 | TargetIndex += SymbolTableOffset[sheader.sh_link]; 376 | } 377 | 378 | // Find section 379 | if (sheader.sh_info < this->NSections) { 380 | Section = SectionNumberTranslate[sheader.sh_info]; 381 | } 382 | else { 383 | // Not found. Try to let disasm find by absolute address 384 | Section = ASM_SEGMENT_IMGREL; 385 | if (Offset < (uint32)ImageBase) Offset += (uint32)ImageBase; 386 | } 387 | 388 | // Get relocation type and size 389 | uint32 Type = 0; 390 | uint32 Size = 0; 391 | if (this->WordSize == 32) { 392 | switch (rel.r_type) { 393 | case R_386_RELATIVE: // Adjust by program base 394 | Type = 0x21; Size = 4; 395 | break; 396 | case R_386_JMP_SLOT: // Create PLT entry 397 | Type = 0x41; Size = 4; 398 | break; 399 | case R_386_PLT32: // Self-relative to PLT 400 | Type = 0x2002; Size = 4; 401 | break; 402 | case R_386_32: 403 | // Direct 32 bit 404 | Type = 1; Size = 4; 405 | break; 406 | case R_386_PC32: 407 | // Self-relative 32 bit 408 | Type = 2; Size = 4; 409 | break; 410 | case R_386_GOTPC: 411 | // Self-relative offset to GOT 412 | Type = 0x1002; Size = 4; 413 | break; 414 | case R_386_IRELATIVE: 415 | // Reference to Gnu indirect function 416 | Type = 0x81; Size = 4; 417 | break; 418 | case R_386_GLOB_DAT: 419 | case R_386_GOT32: 420 | case R_386_GOTOFF: 421 | // Create GOT entry 422 | Type = 0x1001; Size = 4; 423 | break; 424 | } 425 | } 426 | else { 427 | // 64 bit 428 | switch (rel.r_type) { 429 | case R_X86_64_RELATIVE: // Adjust by program base 430 | Type = 0x21; Size = 8; 431 | break; 432 | case R_X86_64_JUMP_SLOT: // Create PLT entry 433 | Type = 0x41; Size = 8; 434 | break; 435 | case R_X86_64_64: 436 | // Direct 64 bit 437 | Type = 1; Size = 8; 438 | break; 439 | case R_X86_64_PC32: 440 | // Self relative 32 bit signed 441 | Type = 2; Size = 4; 442 | break; 443 | case R_X86_64_32: case R_X86_64_32S: 444 | // Direct 32 bit zero extended or sign extend 445 | Type = 1; Size = 4; 446 | break; 447 | case R_X86_64_16: 448 | // Direct 16 bit zero extended 449 | Type = 1; Size = 2; 450 | break; 451 | case R_X86_64_PC16: 452 | // 16 bit sign extended pc relative 453 | Type = 2; Size = 2; 454 | break; 455 | case R_X86_64_8: 456 | // Direct 8 bit sign extended 457 | Type = 1; Size = 1; 458 | break; 459 | case R_X86_64_PC8: 460 | // 8 bit sign extended pc relative 461 | Type = 2; Size = 1; 462 | break; 463 | case R_X86_64_GOTPCREL: 464 | // Self relative 32 bit signed offset to GOT entry 465 | Type = 0x1002; Size = 4; 466 | break; 467 | case R_X86_64_IRELATIVE: 468 | // Reference to Gnu indirect function 469 | Type = 0x81; Size = 4; 470 | break; 471 | case R_X86_64_PLT32: // Self-relative to PLT 472 | Type = 0x2002; Size = 4; 473 | break; 474 | case R_X86_64_GLOB_DAT: // Create GOT entry 475 | case R_X86_64_GOT32: 476 | Type = 0x1001; Size = 4; 477 | break; 478 | } 479 | } 480 | 481 | // Check if offset is absolute or section relative 482 | if (ImageBase && Offset > (uint32)ImageBase) { 483 | // Offset is absolute address 484 | if (Section > 0 && (uint32)Section < this->NSections 485 | && Offset >= (uint32)(this->SectionHeaders[Section].sh_addr) 486 | && Offset - (uint32)(this->SectionHeaders[Section].sh_addr) < (uint32)(this->SectionHeaders[Section].sh_size)) { 487 | // Change to section relative offset 488 | Offset -= (uint32)(this->SectionHeaders[Section].sh_addr); 489 | } 490 | else { 491 | // Inconsistent. Let Disasm try to find the address 492 | Section = ASM_SEGMENT_IMGREL; 493 | Offset -= (uint32)ImageBase; 494 | } 495 | } 496 | 497 | // Save relocation record 498 | Disasm.AddRelocation(Section, Offset, Addend, Type, Size, TargetIndex); 499 | } 500 | } 501 | } 502 | } 503 | 504 | 505 | // MakeImportList 506 | template 507 | void CELF2ASM::MakeImportList() { 508 | // Make imported symbols for executable files 509 | } 510 | 511 | // MakeExportList 512 | template 513 | void CELF2ASM::MakeExportList() { 514 | // Make exported symbols for executable files 515 | } 516 | 517 | // MakeListLabels 518 | template 519 | void CELF2ASM::MakeListLabels() { 520 | // Attach names to all image directories 521 | } 522 | 523 | 524 | // Make template instances for 32 and 64 bits 525 | template class CELF2ASM; 526 | template class CELF2ASM; 527 | -------------------------------------------------------------------------------- /src/elf.cpp: -------------------------------------------------------------------------------- 1 | /**************************** elf.cpp ********************************* 2 | * Author: Agner Fog 3 | * Date created: 2006-07-18 4 | * Last modified: 2009-07-15 5 | * Project: objconv 6 | * Module: elf.cpp 7 | * Description: 8 | * Module for reading ELF files 9 | * 10 | * Class CELF is used for reading, interpreting and dumping ELF files. 11 | * 12 | * Copyright 2006-2009 GNU General Public License http://www.gnu.org/licenses 13 | *****************************************************************************/ 14 | #include "stdafx.h" 15 | // All functions in this module are templated to make two versions: 32 and 64 bits. 16 | // See instantiations at the end of this file. 17 | 18 | 19 | // File class names 20 | SIntTxt ELFFileClassNames[] = { 21 | {ELFCLASSNONE, "None"}, 22 | {ELFCLASS32, "32-bit object"}, 23 | {ELFCLASS64, "64-bit object"} 24 | }; 25 | 26 | // Data encoding names 27 | SIntTxt ELFDataEncodeNames[] = { 28 | {ELFDATANONE, "None"}, 29 | {ELFDATA2LSB, "Little Endian"}, 30 | {ELFDATA2MSB, "Big Endian"} 31 | }; 32 | 33 | // ABI names 34 | SIntTxt ELFABINames[] = { 35 | {ELFOSABI_SYSV, "System V"}, 36 | {ELFOSABI_HPUX, "HP-UX"}, 37 | {ELFOSABI_ARM, "ARM"}, 38 | {ELFOSABI_STANDALONE,"Embedded"}, 39 | }; 40 | 41 | // File type names 42 | SIntTxt ELFFileTypeNames[] = { 43 | {ET_NONE, "None"}, 44 | {ET_REL, "Relocatable"}, 45 | {ET_EXEC, "Executable"}, 46 | {ET_DYN, "Shared object"}, 47 | {ET_CORE, "Core file"} 48 | }; 49 | 50 | // Section type names 51 | SIntTxt ELFSectionTypeNames[] = { 52 | {SHT_NULL, "None"}, 53 | {SHT_PROGBITS, "Program data"}, 54 | {SHT_SYMTAB, "Symbol table"}, 55 | {SHT_STRTAB, "String table"}, 56 | {SHT_RELA, "Relocation w addends"}, 57 | {SHT_HASH, "Symbol hash table"}, 58 | {SHT_DYNAMIC, "Dynamic linking info"}, 59 | {SHT_NOTE, "Notes"}, 60 | {SHT_NOBITS, "bss"}, 61 | {SHT_REL, "Relocation entries"}, 62 | {SHT_SHLIB, "Reserved"}, 63 | {SHT_DYNSYM, "Dynamic linker symbol table"}, 64 | {SHT_INIT_ARRAY, "Array of constructors"}, 65 | {SHT_FINI_ARRAY, "Array of destructors"}, 66 | {SHT_PREINIT_ARRAY, "Array of pre-constructors"}, 67 | {SHT_GROUP, "Section group"}, 68 | {SHT_SYMTAB_SHNDX, "Extended section indices"} 69 | }; 70 | 71 | // Section flag names 72 | SIntTxt ELFSectionFlagNames[] = { 73 | {SHF_WRITE, "Writeable"}, 74 | {SHF_ALLOC, "Allocate"}, 75 | {SHF_EXECINSTR, "Executable"}, 76 | {SHF_MERGE, "Merge"}, 77 | {SHF_STRINGS, "Strings"}, 78 | {SHF_INFO_LINK, "sh_info"}, 79 | {SHF_LINK_ORDER, "Preserve order"}, 80 | {SHF_OS_NONCONFORMING,"OS specific"} 81 | }; 82 | 83 | // Symbol binding names 84 | SIntTxt ELFSymbolBindingNames[] = { 85 | {STB_LOCAL, "Local"}, 86 | {STB_GLOBAL, "Global"}, 87 | {STB_WEAK, "Weak"} 88 | }; 89 | 90 | // Symbol Type names 91 | SIntTxt ELFSymbolTypeNames[] = { 92 | {STT_NOTYPE, "None"}, 93 | {STT_OBJECT, "Object"}, 94 | {STT_FUNC, "Function"}, 95 | {STT_SECTION, "Section"}, 96 | {STT_FILE, "File"}, 97 | {STT_COMMON, "Common"}, 98 | {STT_GNU_IFUNC, "Indirect function/dispatcher"} 99 | }; 100 | 101 | // Relocation type names x86 32 bit 102 | SIntTxt ELF32RelocationNames[] = { 103 | {R_386_NONE, "None"}, 104 | {R_386_32, "Absolute 32 bit"}, 105 | {R_386_PC32, "Self-relative 32 bit"}, 106 | {R_386_GOT32, "32 bit GOT entry"}, 107 | {R_386_PLT32, "32 bit PLT address"}, 108 | {R_386_COPY, "Copy symbol at runtime"}, 109 | {R_386_GLOB_DAT, "Create GOT entry"}, 110 | {R_386_JMP_SLOT, "Create PLT entry"}, 111 | {R_386_RELATIVE, "Adjust by image base"}, 112 | {R_386_GOTOFF, "32 bit offset to GOT"}, 113 | {R_386_GOTPC, "32 bit PC relative offset to GOT"}, 114 | {R_386_IRELATIVE, "32 bit ref. to indirect function PLT"} 115 | }; 116 | 117 | // Relocation type names x86 64 bit 118 | SIntTxt ELF64RelocationNames[] = { 119 | {R_X86_64_NONE, "None"}, 120 | {R_X86_64_64, "Direct 64 bit"}, 121 | {R_X86_64_PC32, "Self relative 32 bit signed"}, 122 | {R_X86_64_GOT32, "32 bit GOT entry"}, 123 | {R_X86_64_PLT32, "32 bit PLT address"}, 124 | {R_X86_64_COPY, "Copy symbol at runtime"}, 125 | {R_X86_64_GLOB_DAT, "Create GOT entry"}, 126 | {R_X86_64_JUMP_SLOT, "Create PLT entry"}, 127 | {R_X86_64_RELATIVE, "Adjust by program base"}, 128 | {R_X86_64_GOTPCREL, "32 bit signed pc relative offset to GOT"}, 129 | {R_X86_64_32, "Direct 32 bit zero extended"}, 130 | {R_X86_64_32S, "Direct 32 bit sign extended"}, 131 | {R_X86_64_16, "Direct 16 bit zero extended"}, 132 | {R_X86_64_PC16, "16 bit sign extended pc relative"}, 133 | {R_X86_64_8, "Direct 8 bit sign extended"}, 134 | {R_X86_64_PC8, "8 bit sign extended pc relative"}, 135 | {R_X86_64_IRELATIVE, "32 bit ref. to indirect function PLT"} 136 | }; 137 | 138 | 139 | // Machine names 140 | SIntTxt ELFMachineNames[] = { 141 | {EM_NONE, "None"}, // No machine 142 | {EM_M32, "AT&T WE 32100"}, 143 | {EM_SPARC, "SPARC"}, 144 | {EM_386, "Intel x86"}, 145 | {EM_68K, "Motorola m68k"}, 146 | {EM_88K, "Motorola m88k"}, 147 | {EM_860, "MIPS R3000 big-endian"}, 148 | {EM_MIPS, "MIPS R3000 big-endian"}, 149 | {EM_S370, "IBM System/370"}, 150 | {EM_MIPS_RS3_LE, "NMIPS R3000 little-endianone"}, 151 | {EM_PARISC, "HPPA"}, 152 | {EM_VPP500, "Fujitsu VPP500"}, 153 | {EM_SPARC32PLUS, "Sun v8plus"}, 154 | {EM_960, "Intel 80960"}, 155 | {EM_PPC, "PowerPC"}, 156 | {EM_PPC64, "PowerPC 64-bit"}, 157 | {EM_S390, "IBM S390"}, 158 | {EM_V800, "NEC V800"}, 159 | {EM_FR20, "Fujitsu FR20"}, 160 | {EM_RH32, "TRW RH-32"}, 161 | {EM_RCE, "Motorola RCE"}, 162 | {EM_ARM, "ARM"}, 163 | {EM_FAKE_ALPHA, "Digital Alpha"}, 164 | {EM_SH, "Hitachi SH"}, 165 | {EM_SPARCV9, "SPARC v9 64-bit"}, 166 | {EM_TRICORE, "Siemens Tricore"}, 167 | {EM_ARC, "Argonaut RISC"}, 168 | {EM_H8_300, "Hitachi H8/300"}, 169 | {EM_H8_300H, "Hitachi H8/300H"}, 170 | {EM_H8S, "Hitachi H8S"}, 171 | {EM_H8_500, "EM_H8_500"}, 172 | {EM_IA_64, "Intel IA64"}, 173 | {EM_MIPS_X, "Stanford MIPS-X"}, 174 | {EM_COLDFIRE, "Motorola Coldfire"}, 175 | {EM_68HC12, "Motorola M68HC12"}, 176 | {EM_MMA, "Fujitsu MMA"}, 177 | {EM_PCP, "Siemens PCP"}, 178 | {EM_NCPU, "Sony nCPU"}, 179 | {EM_NDR1, "Denso NDR1"}, 180 | {EM_STARCORE, "Motorola Start*Core"}, 181 | {EM_ME16, "Toyota ME16"}, 182 | {EM_ST100, "ST100"}, 183 | {EM_TINYJ, "Tinyj"}, 184 | {EM_X86_64, "x86-64"}, 185 | {EM_PDSP, "Sony DSP"}, 186 | {EM_FX66, "Siemens FX66"}, 187 | {EM_ST9PLUS, "ST9+ 8/16"}, 188 | {EM_ST7, "ST7 8"}, 189 | {EM_68HC16, "MC68HC16"}, 190 | {EM_68HC11, "MC68HC11"}, 191 | {EM_68HC08, "MC68HC08"}, 192 | {EM_68HC05, "MC68HC05"}, 193 | {EM_SVX, "SVx"}, 194 | {EM_AT19, "ST19"}, 195 | {EM_VAX, "VAX"}, 196 | {EM_CRIS, "Axis"}, 197 | {EM_JAVELIN, "Infineon"}, 198 | {EM_FIREPATH, "Element 14"}, 199 | {EM_ZSP, "LSI Logic"}, 200 | {EM_HUANY, "Harvard"}, 201 | {EM_PRISM, "SiTera Prism"}, 202 | {EM_AVR, "Atmel AVR"}, 203 | {EM_FR30, "FR30"}, 204 | {EM_D10V, "D10V"}, 205 | {EM_D30V, "D30V"}, 206 | {EM_V850, "NEC v850"}, 207 | {EM_M32R, "M32R"}, 208 | {EM_MN10300, "MN10300"}, 209 | {EM_MN10200, "MN10200"}, 210 | {EM_PJ, "picoJava"}, 211 | {EM_ALPHA, "Alpha"} 212 | }; 213 | 214 | 215 | // Class CELF members: 216 | // Constructor 217 | template 218 | CELF::CELF() { 219 | memset(this, 0, sizeof(*this)); 220 | } 221 | 222 | // ParseFile 223 | template 224 | void CELF::ParseFile(){ 225 | // Load and parse file buffer 226 | uint32 i; 227 | FileHeader = *(TELF_Header*)Buf(); // Copy file header 228 | NSections = FileHeader.e_shnum; 229 | SectionHeaders.SetNum(NSections); // Allocate space for section headers 230 | SectionHeaders.SetZero(); 231 | uint32 Symtabi = 0; // Index to symbol table 232 | 233 | // Find section headers 234 | SectionHeaderSize = FileHeader.e_shentsize; 235 | if (SectionHeaderSize <= 0) err.submit(2033); 236 | uint32 SectionOffset = uint32(FileHeader.e_shoff); 237 | 238 | for (i = 0; i < NSections; i++) { 239 | SectionHeaders[i] = Get(SectionOffset); 240 | SectionOffset += SectionHeaderSize; 241 | 242 | if (SectionHeaders[i].sh_type == SHT_SYMTAB) { 243 | // Symbol table found 244 | Symtabi = i; 245 | } 246 | } 247 | SecStringTable = Buf() + uint32(SectionHeaders[FileHeader.e_shstrndx].sh_offset); 248 | SecStringTableLen = uint32(SectionHeaders[FileHeader.e_shstrndx].sh_size); 249 | if (SectionOffset > GetDataSize()) { 250 | err.submit(2110); // Section table points to outside file 251 | } 252 | if (Symtabi) { 253 | // Save offset to symbol table 254 | SymbolTableOffset = (uint32)(SectionHeaders[Symtabi].sh_offset); 255 | SymbolTableEntrySize = (uint32)(SectionHeaders[Symtabi].sh_entsize); // Entry size of symbol table 256 | if (SymbolTableEntrySize == 0) {err.submit(2034); return;} // Avoid division by zero 257 | SymbolTableEntries = uint32(SectionHeaders[Symtabi].sh_size) / SymbolTableEntrySize; 258 | // Find associated string table 259 | uint32 Stringtabi = SectionHeaders[Symtabi].sh_link; 260 | if (Stringtabi < NSections) { 261 | SymbolStringTableOffset = (uint32)(SectionHeaders[Stringtabi].sh_offset); 262 | SymbolStringTableSize = (uint32)(SectionHeaders[Stringtabi].sh_size); 263 | } 264 | else { 265 | Symtabi = 0; // Error 266 | } 267 | } 268 | } 269 | 270 | 271 | // Dump 272 | template 273 | void CELF::Dump(int options) { 274 | if (options & DUMP_FILEHDR) { 275 | // File header 276 | printf("\nDump of ELF file %s", FileName); 277 | printf("\n-----------------------------------------------"); 278 | printf("\nFile size: %i", GetDataSize()); 279 | printf("\nFile header:"); 280 | printf("\nFile class: %s, Data encoding: %s, ELF version %i, ABI: %s, ABI version %i", 281 | Lookup(ELFFileClassNames, FileHeader.e_ident[EI_CLASS]), 282 | Lookup(ELFDataEncodeNames, FileHeader.e_ident[EI_DATA]), 283 | FileHeader.e_ident[EI_VERSION], 284 | Lookup(ELFABINames, FileHeader.e_ident[EI_OSABI]), 285 | FileHeader.e_ident[EI_ABIVERSION]); 286 | 287 | printf("\nFile type: %s, Machine: %s, version: %i", 288 | Lookup(ELFFileTypeNames, FileHeader.e_type), 289 | Lookup(ELFMachineNames, FileHeader.e_machine), 290 | FileHeader.e_version); 291 | printf("\nNumber of sections: %2i, Processor flags: 0x%X", 292 | NSections, FileHeader.e_flags); 293 | } 294 | 295 | if (options & DUMP_SECTHDR) { 296 | // Dump section headers 297 | printf("\n\nSection headers:"); 298 | for (uint32 sc = 0; sc < NSections; sc++) { 299 | // Get copy of 32-bit header or converted 64-bit header 300 | TELF_SectionHeader sheader = SectionHeaders[sc]; 301 | uint32 entrysize = (uint32)(sheader.sh_entsize); 302 | uint32 namei = sheader.sh_name; 303 | if (namei >= SecStringTableLen) {err.submit(2112); break;} 304 | printf("\n%2i Name: %-18s Type: %s", sc, SecStringTable + namei, 305 | Lookup(ELFSectionTypeNames, sheader.sh_type)); 306 | if (sheader.sh_flags) { 307 | printf("\n Flags: 0x%X:", uint32(sheader.sh_flags)); 308 | for (int fi = 1; fi < (1 << 30); fi <<= 1) { 309 | if (uint32(sheader.sh_flags) & fi) { 310 | printf(" %s", Lookup(ELFSectionFlagNames,fi)); 311 | } 312 | } 313 | } 314 | if (sheader.sh_addr) { 315 | printf("\n Address: 0x%X", uint32(sheader.sh_addr)); 316 | } 317 | if (sheader.sh_offset || sheader.sh_size) { 318 | printf("\n FileOffset: 0x%X, Size: 0x%X", 319 | uint32(sheader.sh_offset), uint32(sheader.sh_size)); 320 | } 321 | if (sheader.sh_addralign) { 322 | printf("\n Alignment: 0x%X", uint32(sheader.sh_addralign)); 323 | } 324 | if (sheader.sh_entsize) { 325 | printf("\n Entry size: 0x%X", uint32(sheader.sh_entsize)); 326 | switch (sheader.sh_type) { 327 | case SHT_DYNAMIC: 328 | printf("\n String table: %i", sheader.sh_link); 329 | break; 330 | case SHT_HASH: 331 | printf("\n Symbol table: %i", sheader.sh_link); 332 | break; 333 | case SHT_REL: case SHT_RELA: 334 | printf("\n Symbol table: %i, Reloc. section: %i", 335 | sheader.sh_link, sheader.sh_info); 336 | break; 337 | case SHT_SYMTAB: case SHT_DYNSYM: 338 | printf("\n Symbol string table: %i, First global symbol: %i", 339 | sheader.sh_link, sheader.sh_info); 340 | break; 341 | default: 342 | if (sheader.sh_link) { 343 | printf("\n Link: %i", sheader.sh_link); 344 | } 345 | if (sheader.sh_info) { 346 | printf("\n Info: %i", sheader.sh_info); 347 | } 348 | } 349 | } 350 | if (sheader.sh_type == SHT_STRTAB && (options & DUMP_STRINGTB)) { 351 | // Print string table 352 | printf("\n String table:"); 353 | char * p = Buf() + uint32(sheader.sh_offset) + 1; 354 | uint32 nread = 1, len; 355 | while (nread < uint32(sheader.sh_size)) { 356 | len = (uint32)strlen(p); 357 | printf(" >>%s<<", p); 358 | nread += len + 1; 359 | p += len + 1; 360 | } 361 | } 362 | if ((sheader.sh_type==SHT_SYMTAB || sheader.sh_type==SHT_DYNSYM) && (options & DUMP_SYMTAB)) { 363 | // Dump symbol table 364 | 365 | // Find associated string table 366 | if (sheader.sh_link >= (uint32)NSections) {err.submit(2035); sheader.sh_link = 0;} 367 | int8 * strtab = Buf() + uint32(SectionHeaders[sheader.sh_link].sh_offset); 368 | 369 | // Find symbol table 370 | uint32 symtabsize = (uint32)(sheader.sh_size); 371 | int8 * symtab = Buf() + uint32(sheader.sh_offset); 372 | int8 * symtabend = symtab + symtabsize; 373 | if (entrysize < sizeof(TELF_Symbol)) {err.submit(2033); entrysize = sizeof(TELF_Symbol);} 374 | 375 | printf("\n Symbols:"); 376 | // Loop through symbol table 377 | int symi; // Symbol number 378 | for (symi = 0; symtab < symtabend; symtab += entrysize, symi++) { 379 | // Copy 32 bit symbol table entry or convert 64 bit entry 380 | TELF_Symbol sym = *(TELF_Symbol*)symtab; 381 | int type = sym.st_type; 382 | int binding = sym.st_bind; 383 | if (*(strtab + sym.st_name)) { 384 | printf("\n %2i Name: %s,", symi, strtab + sym.st_name);} 385 | else { 386 | printf("\n %2i Unnamed,", symi);} 387 | if (sym.st_value || type == STT_OBJECT || type == STT_FUNC || type == STT_GNU_IFUNC || int16(sym.st_shndx) < 0) 388 | printf(" Value: 0x%X", uint32(sym.st_value)); 389 | if (sym.st_size) printf(" Size: %i", uint32(sym.st_size)); 390 | if (sym.st_other) printf(" Other: 0x%X", sym.st_other); 391 | if (int16(sym.st_shndx) >= 0) printf(" Section: %i", sym.st_shndx); 392 | else { // Special segment values 393 | switch (int16(sym.st_shndx)) { 394 | case SHN_ABS: 395 | printf(" Absolute,"); break; 396 | case SHN_COMMON: 397 | printf(" Common,"); break; 398 | case SHN_XINDEX: 399 | printf(" Index in extra table,"); break; 400 | default: 401 | printf(" Section: 0x%X", sym.st_shndx); 402 | } 403 | } 404 | if (sym.st_type || sym.st_bind) { 405 | printf(" Type: %s, Binding: %s", 406 | Lookup(ELFSymbolTypeNames, type), 407 | Lookup(ELFSymbolBindingNames, binding)); 408 | } 409 | } 410 | } 411 | if ((sheader.sh_type==SHT_REL || sheader.sh_type==SHT_RELA ) && (options & DUMP_RELTAB)) { 412 | printf("\n Relocations:"); 413 | int8 * reltab = Buf() + uint32(sheader.sh_offset); 414 | int8 * reltabend = reltab + uint32(sheader.sh_size); 415 | uint32 expectedentrysize = sheader.sh_type == SHT_RELA ? 416 | sizeof(TELF_Relocation) : // Elf32_Rela, Elf64_Rela 417 | sizeof(TELF_Relocation) - WordSize/8; // Elf32_Rel, Elf64_Rel 418 | if (entrysize < expectedentrysize) {err.submit(2033); entrysize = expectedentrysize;} 419 | 420 | // Loop through entries 421 | for (; reltab < reltabend; reltab += entrysize) { 422 | // Copy relocation table entry with or without addend 423 | TELF_Relocation rel; rel.r_addend = 0; 424 | memcpy(&rel, reltab, entrysize); 425 | printf ("\n Offset: 0x%X, Symbol: %i, Name: %s\n Type: %s", 426 | uint32(rel.r_offset), rel.r_sym, SymbolName(rel.r_sym), 427 | (WordSize == 32) ? 428 | Lookup (ELF32RelocationNames, rel.r_type) : 429 | Lookup (ELF64RelocationNames, rel.r_type)); 430 | if (rel.r_addend) printf (", Addend: 0x%X", uint32(rel.r_addend)); 431 | 432 | // Find inline addend 433 | TELF_SectionHeader relsheader = SectionHeaders[sheader.sh_info]; 434 | uint32 relsoffset = uint32(relsheader.sh_offset); 435 | if (relsoffset+rel.r_offset < GetDataSize()) { 436 | int32 * piaddend = (int32*)(Buf()+relsoffset+rel.r_offset); 437 | if (* piaddend) printf (", Inline addend: 0x%X", * piaddend); 438 | } 439 | } 440 | } 441 | } 442 | } 443 | } 444 | 445 | 446 | // PublicNames 447 | template 448 | void CELF::PublicNames(CMemoryBuffer * Strings, CSList * Index, int m) { 449 | // Make list of public names 450 | // Interpret header: 451 | ParseFile(); 452 | 453 | // Loop through section headers 454 | for (uint32 sc = 0; sc < NSections; sc++) { 455 | // Get copy of 32-bit header or converted 64-bit header 456 | TELF_SectionHeader sheader = SectionHeaders[sc]; 457 | uint32 entrysize = uint32(sheader.sh_entsize); 458 | 459 | if (sheader.sh_type==SHT_SYMTAB || sheader.sh_type==SHT_DYNSYM) { 460 | // Dump symbol table 461 | 462 | // Find associated string table 463 | if (sheader.sh_link >= (uint32)NSections) {err.submit(2035); sheader.sh_link = 0;} 464 | int8 * strtab = Buf() + uint32(SectionHeaders[sheader.sh_link].sh_offset); 465 | 466 | // Find symbol table 467 | uint32 symtabsize = uint32(sheader.sh_size); 468 | int8 * symtab = Buf() + uint32(sheader.sh_offset); 469 | int8 * symtabend = symtab + symtabsize; 470 | if (entrysize < sizeof(TELF_Symbol)) {err.submit(2033); entrysize = sizeof(TELF_Symbol);} 471 | 472 | // Loop through symbol table 473 | for (int symi = 0; symtab < symtabend; symtab += entrysize, symi++) { 474 | // Copy 32 bit symbol table entry or convert 64 bit entry 475 | TELF_Symbol sym = *(TELF_Symbol*)symtab; 476 | int type = sym.st_type; 477 | int binding = sym.st_bind; 478 | if (int16(sym.st_shndx) > 0 479 | && type != STT_SECTION && type != STT_FILE 480 | && (binding == STB_GLOBAL || binding == STB_WEAK)) { 481 | // Public symbol found 482 | SStringEntry se; 483 | se.Member = m; 484 | // Store name 485 | se.String = Strings->PushString(strtab + sym.st_name); 486 | // Store name index 487 | Index->Push(se); 488 | } 489 | } 490 | } 491 | } 492 | } 493 | 494 | // SymbolName 495 | template 496 | const char * CELF::SymbolName(uint32 index) { 497 | // Get name of symbol. (ParseFile() must be called first) 498 | const char * symname = "?"; // Symbol name 499 | uint32 symi; // Symbol index 500 | uint32 stri; // String index 501 | if (SymbolTableOffset) { 502 | symi = SymbolTableOffset + index * SymbolTableEntrySize; 503 | if (symi < GetDataSize()) { 504 | stri = Get(symi).st_name; 505 | if (stri < SymbolStringTableSize) { 506 | symname = Buf() + SymbolStringTableOffset + stri; 507 | } 508 | } 509 | } 510 | return symname; 511 | } 512 | 513 | 514 | // Make template instances for 32 and 64 bits 515 | template class CELF; 516 | template class CELF; 517 | --------------------------------------------------------------------------------