first rough draft of README.md - first rough draft of example1
parent
d75ab807ce
commit
642f3db19b
190
README.md
190
README.md
|
|
@ -1,3 +1,189 @@
|
|||
### C Scripting
|
||||
# C Scripting Introduction
|
||||
|
||||
TODO(allen):
|
||||
"C Scripting" is a technique I developed to solve a *problem* in C programming. The *problem* doesn't have a well known name, and I think many programmers only experience this problem as an intuitively felt limitation, and not as a *problem*. To introduce this idea properly I will have to spell out the *problem*, which I will get to shortly. I named my answer to this *problem* "C Scripting" because it feels like a step towards the kind of expressive freedom that one gets by choosing, or hybridizing with, a scripting language. In this introduction I name and describe the *problem* then I describe the basic idea of a C Scripting system. Past the introduction, the repository is filled with example code, further discussions of design tradeoffs, and possibilities for future improvements of the technique.
|
||||
|
||||
### Introduction: The Code-Data Binding Problem
|
||||
|
||||
The *problem* I am talking about is the problem of creating and maintaining a structure of code-data relationships. It'll be easier to see what I mean after some examples.
|
||||
|
||||
Think of what you do to setup a new program with just a command line interface. You have a set of flags to implement, each needs a name and/or an abbreviation, maybe some expected argument type, some help menu text, and of course some way of binding information from the interface into the "main computation".
|
||||
|
||||
`CLIFlag = (name:String & abbr:String & arg_type:ArgType & desc:String & ???:???)`
|
||||
|
||||
The first few pieces are easy enough to understand, but is that last piece that does the "binding into the main computation"? Let's answer that by looking at how systems like these tend to be done:
|
||||
|
||||
**Immediate Mode CLI**
|
||||
```
|
||||
{
|
||||
if (cli_flag(clictx, "fast", "F", ArgType_None, "go as fast as possible")){
|
||||
// do some init path stuff
|
||||
}
|
||||
if (cli_flag(clictx, "start_time", "S", ArgType_TimeStamp,
|
||||
"set the time where the output stream begins (>= 0:00) (default 0:00)")){
|
||||
TimeStamp time_stamp = cli_read_arg_TimeStamp(clictx);
|
||||
// do some init path stuff
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Here we put the data literals in as parameters to a function, and use the block of an if statement to attach some binding into the rest of the software. The hard part here will be using these expressions to run the help menu. There's a couple ways to do it, but it has to run a little "sideways" through the system.
|
||||
|
||||
**Table Driven CLI**
|
||||
```
|
||||
void cli_p_fast(CLICtx *ctx, void *arg){ /*...*/ }
|
||||
void cli_p_state_time(CLICtx *ctx, void *arg){ /*...*/ }
|
||||
|
||||
CLIFlag flags[] = {
|
||||
{ "fast", "F", ArgType_None, "go as fast as possible", cli_p_fast },
|
||||
{ "start_time", "S", ArgType_TimeStamp,
|
||||
"set the time where the output stream begins (>= 0:00) (default 0:00)", cli_p_state_time },
|
||||
}
|
||||
```
|
||||
|
||||
Here we put the data literals together with some "hooks" (function pointers) and can specify the whole thing as a global data table. Except the "binding into the main computation" is through this function pointer now, and the function body is unhappily far away from the declaration, and since the `ArgType` couples to the function body, you've got a new long-range matching problem to add to your maintenance burden. The nice thing here of course is your help menu is going to be trivial to write, and other comprehension tasks like checking for duplicate abbreviations will be easy too.
|
||||
|
||||
**Metaprogramming**
|
||||
```
|
||||
CLI_FLAG(fast, "F", ArgType_None, "go as fast as possible"){
|
||||
// ...
|
||||
}
|
||||
CLI_FLAG(start_time, "S", ArgType_TimeStamp,
|
||||
"set the time where the output stream begins (>= 0:00) (default 0:00)"){
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
This is the sort of thing I did in the 4coder command system. You get the best of both worlds from the previous two systems, but you have to adopt an entire metaprogram into your build. The metaprogram scans the code for `CLI_FLAG` and parses out the details to generate a data table like in the second example. Then you build that data table into your final program. In the final program, the macro expands into a hook function with the name given by the first part of the macro, and the rest discarded. The downside now is that a whole new metaprogram is a heavy thing, and it looks like you'll need to expand that metaprogram for each one of these you use. With some refinement it might be pretty reusable -- but even one metaprogram is a downside.
|
||||
|
||||
**There are many other solutions.** You can bind with an enum and switch instead of hooks. You can bind with pointers to data output slots in the main context, and leave all the computation downstream. You can declare the flags in a table without code binding, then after the parse use extractors that read out the parsed data to effect the main context. The funny thing is, in all my years with C, none of them feel totally satisfying to work with, you're always trading off.
|
||||
|
||||
**This comes up in a lot of cases too.** In a plugin system, you usually want a plugin to register some new operations in one or multiple categories. How do you bind the new operations with their interface information in the plugin and process that in the core? In a game or simulation you may have systems like event handlers, entity behavior hooks, procedural generation nodes, or context specific rules.
|
||||
|
||||
### Introduction: A C Scripting System
|
||||
|
||||
A C Scripting system allows for code written like this:
|
||||
```
|
||||
MY_THING_SCRIPT(foo, FooBarGroup, "Generates a foo and increments the foo counter"){
|
||||
out->name = str8_lit("foo");
|
||||
ctx->foo += 1;
|
||||
}
|
||||
```
|
||||
|
||||
And in a true C Scripting system, there are two more requirements. One it should work *without* any code generation. And two, there should be some kind of automated "registration" process that builds a data structure that lets me "comprehend" the entire set of these things. In other words there should be no manually written (or generated) list that looks like this:
|
||||
```
|
||||
{
|
||||
register_my_thing(mythings, &foo);
|
||||
register_my_thing(mythings, &bar);
|
||||
}
|
||||
```
|
||||
|
||||
There's no way to achieve this in standard C. However with one non-standard trick we can get there in a fairly satisfying way. And I've tested out `clang` and `cl` for compilers, `clang` and `link` for linkers, and various combinations of optimizations and link time optimizations, and found that this non-standard trick continues to behave as expected across the board. I have yet to test this out on a Linux or Mac machine, or on an a machine with an architecture other than an ARM64, so the research on this technique isn't *finished* but it's looking *very good*.
|
||||
|
||||
**Data Sections**
|
||||
|
||||
The plan is to set aside a new *data section* in the final executable that is populated only by instances of a particular struct. This is the key non-standardized compiler feature that I need. This data section then acts as an array of this struct, with one element in the array for each global you defined this way:
|
||||
|
||||
```
|
||||
SECTION(".mything") MyThing foo = {
|
||||
"foo", MY_THING_GROUP(FooBarGroup), "Generates a foo and increments the foo counter", foo_hook
|
||||
};
|
||||
SECTION(".mything") MyThing bar = {
|
||||
"bar", MY_THING_GROUP(FooBarGroup), "Generates a bar and decrements the foo counter", bar_hook
|
||||
};
|
||||
```
|
||||
|
||||
That's the plan - but that alone isn't enough. This way I would still have to put the hook in by name, and leave it defined somewhere else. But the part that I want to emphasize here is that the data section `.mything` now contains an array of these `MyThing` structs. If we ever want to do work over all the `MyThing`s we just have to locate that data section in our program -- and yes that is something we *can* do!
|
||||
|
||||
The other cool thing here is that these are still *also* global variables! They can be referenced by their name from anywhere, and what you get is like a hardcoded reference to a slot in that special array.
|
||||
|
||||
We can achieve this much with a macro like this:
|
||||
```
|
||||
#if COMPILER_CLANG || COMPILER_GCC
|
||||
# define SECTION(N) __attribute__((__section__(N)))
|
||||
#elif COMPILER_CL
|
||||
# define SECTION(N) __declspec(allocate(N))
|
||||
#endif
|
||||
```
|
||||
|
||||
In the CL compiler you also need to insist that the data section exists by dropping this somewhere:
|
||||
```
|
||||
#pragma section(<section>,read,write)
|
||||
```
|
||||
|
||||
**Accessing the Data**
|
||||
|
||||
That's how we'll declare the data, bind it to the code, and organize it into a comprehendible data structure. To access the data structure we'll need to be able to parse the data structure that describes the module's binary image and find the data section we're looking for. There are two steps to this:
|
||||
|
||||
1. Locate the module's binary image - this involves a conversation with the operating system.
|
||||
2. Parse the image to find the data section - this involves knowledge of the binary file format.
|
||||
|
||||
Despite the fact that this sounds like asking you to dabble in some dark arts -- each of these is relatively easily achieved and abstracted. The final API can be as simple as: `RangePtr selfimg_get_section(String8 name);`
|
||||
|
||||
Personally I've pushed my own system to the point of automating even this part by sticking it in a `BEFORE_MAIN` when I setup the data section, so that my interface just looks like a typed global pointer and count that is initialized to point at the array I need. This is an additional trick - and isn't *necessary*. But I will discuss how and why I did it this way in discussions of the design tradeoffs and future plans.
|
||||
|
||||
Often, but not always, there's another step of processing that I want to run on the data in the array. Sometimes they are incomplete and the hook is actually a constructor that finishes the job. Sometimes they act as extensions to another array or at least relate to one another in ways that I want to index or construct in a higher data structure.
|
||||
|
||||
```
|
||||
{
|
||||
RangePtr range = selfimg_get_section(str8_lit(".mything"));
|
||||
MyThing *my_thing = (MyThing*)range.first;
|
||||
U64 my_thing_count = ((MyThing*)range.first - (MyThing*)range.opl);
|
||||
}
|
||||
```
|
||||
|
||||
**Wrapper Macro With Fused Hook Syntax**
|
||||
|
||||
Next what we do is wrap the data section name and type together into a single macro that does the declaration. With preprocessor stringification and pasting, we can make your syntax more terse now:
|
||||
|
||||
```
|
||||
#define MY_THING_DEF(name,group,desc,hook) \
|
||||
SECTION(".mything") MyThing name = { #name, MY_THING_GROUP(group), #desc, hook }
|
||||
|
||||
MY_THING_DEF(foo, FooBarGroup, "Generates a foo and increments the foo counter", foo_hook);
|
||||
MY_THING_DEF(bar, FooBarGroup, "Generates a bar and decrements the foo counter", bar_hook);
|
||||
```
|
||||
|
||||
Then I want to *fuse* the hook to the macro. To do this the last thing the macro expands has to be the function signature *without* a semi-colon or brace, and I need to be sure the hook is declared *before* the global variable in the special data section so that it can reference the function.
|
||||
|
||||
```
|
||||
#define MY_THING_DEF(name,group,desc,hook) \
|
||||
void hook(MyThingCtx *ctx); \
|
||||
SECTION(".mything") MyThing name = { #name, MY_THING_GROUP(group), #desc, hook }; \
|
||||
void hook(MyThingCtx *ctx)
|
||||
|
||||
MY_THING_DEF(foo, FooBarGroup, "Generates a foo and increments the foo counter", foo_hook){
|
||||
// ...
|
||||
}
|
||||
|
||||
MY_THING_DEF(bar, FooBarGroup, "Generates a bar and decrements the foo counter", bar_hook){
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
And I like to take advantage of preprocessor pasting to free myself from the chore of naming the hook:
|
||||
|
||||
```
|
||||
#define MY_THING_DEF(name,group,desc) \
|
||||
void my_thing_hook__##name(MyThingCtx *ctx); \
|
||||
SECTION(".mything") MyThing name = { #name, MY_THING_GROUP(group), #desc, my_thing_hook__##name }; \
|
||||
void my_thing_hook__##name(MyThingCtx *ctx)
|
||||
|
||||
MY_THING_DEF(foo, FooBarGroup, "Generates a foo and increments the foo counter"){
|
||||
// ...
|
||||
}
|
||||
|
||||
MY_THING_DEF(bar, FooBarGroup, "Generates a bar and decrements the foo counter"){
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
**Reusable C Scripting System**
|
||||
|
||||
The last challenge is to take this idea and make it possible to create and maintain *many* of these special arrays as needed. It turns out most of the setup and wrangling work can be offloaded to a generic set of macros that work the same way as this special case above works. I call one of these "special arrays" a "Symbol Set" and thus I call the headers that introduce this system my "Symbol Set" system. If you can see this, you are currently a member of mr4th.com, and so you should be able to see my the implementation as I have it in my codebase at:
|
||||
|
||||
https://git.mr4th.com/mr4th-members/mr4th/src/branch/main/src/mr4th_symbol_set.h
|
||||
https://git.mr4th.com/mr4th-members/mr4th/src/branch/main/src/mr4th_symbol_set.define.h
|
||||
|
||||
There are so many subtle design choices to make in this system, and it so deeply integrates with base layer concerns, that I suggest learning how to build your own. That's what the rest of this repository is for!
|
||||
|
||||
*-- Allen Webster. April 17th, 2025*
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
@echo off
|
||||
|
||||
set opts=-FC -GR- -EHa- -nologo -Zi
|
||||
set code=%cd%
|
||||
pushd build
|
||||
cl %opts% %code%\src\example1.c -Feexample1
|
||||
popd
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
#!/bin/bash
|
||||
|
||||
code="$PWD"
|
||||
opts=-g
|
||||
cd build > /dev/null
|
||||
g++ $opts $code/example1.c -o example1
|
||||
cd $code > /dev/null
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
version(2);
|
||||
project_name = "example1";
|
||||
patterns = {
|
||||
"*.c",
|
||||
"*.cpp",
|
||||
"*.h",
|
||||
"*.m",
|
||||
"*.bat",
|
||||
"*.sh",
|
||||
"*.4coder",
|
||||
};
|
||||
blacklist_patterns = {
|
||||
".*",
|
||||
};
|
||||
load_paths_base = {
|
||||
{ ".", .relative = true, .recursive = true, },
|
||||
};
|
||||
load_paths = {
|
||||
.win = load_paths_base,
|
||||
.linux = load_paths_base,
|
||||
.mac = load_paths_base,
|
||||
};
|
||||
|
||||
commands = {
|
||||
.build = { .out = "*compilation*", .footer_panel = true, .save_dirty_files = true,
|
||||
.win = "build.bat",
|
||||
.linux = "./build.sh",
|
||||
.mac = "./build.sh", },
|
||||
.run = { .out = "*run*", .footer_panel = false, .save_dirty_files = false,
|
||||
.win = "build\\example1",
|
||||
.linux = "build/example1",
|
||||
.mac = "build/example1", },
|
||||
};
|
||||
fkey_command = {
|
||||
.F1 = "build",
|
||||
.F2 = "run",
|
||||
};
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
////////////////////////////////
|
||||
// Functions
|
||||
|
||||
|
||||
#if OS_WINDOWS
|
||||
# include <Windows.h>
|
||||
# include <userenv.h>
|
||||
# include <psapi.h>
|
||||
#endif
|
||||
|
||||
static String8
|
||||
str8(U8 *str, U64 size){
|
||||
String8 result = {str, size};
|
||||
return(result);
|
||||
}
|
||||
|
||||
static B32
|
||||
str8_match(String8 a, String8 b, U32 flags){
|
||||
B32 result = 0;
|
||||
if (a.size == b.size){
|
||||
U64 size = a.size;
|
||||
result = 1;
|
||||
for (U64 i = 0; i < size; i += 1){
|
||||
U8 ac = a.str[i];
|
||||
U8 bc = b.str[i];
|
||||
if (ac != bc){
|
||||
result = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
#if OS_WINDOWS
|
||||
|
||||
static RangePtr
|
||||
os_this_image(void){
|
||||
RangePtr result = {0};
|
||||
HMODULE module = 0;
|
||||
GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
|
||||
(LPWSTR)os_this_image, &module);
|
||||
if (module != 0){
|
||||
HANDLE process = GetCurrentProcess();
|
||||
MODULEINFO module_info = {0};
|
||||
if (GetModuleInformation(process, module,
|
||||
&module_info, sizeof(module_info))){
|
||||
result.first = (U8*)module_info.lpBaseOfDll;
|
||||
result.opl = result.first + module_info.SizeOfImage;
|
||||
}
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
#else
|
||||
# error os_this_image not implemented for this OS
|
||||
#endif
|
||||
|
||||
#if OS_WINDOWS
|
||||
|
||||
# include "binary/pe/mr4th_pe.h"
|
||||
# include "binary/pe/mr4th_pe.parse.h"
|
||||
# include "binary/pe/mr4th_pe.parse.c"
|
||||
|
||||
static RangePtr
|
||||
selfimg_get_section(RangePtr image, String8 name){
|
||||
RangePtr result = {0};
|
||||
String8 image_str = str8(image.first, image.opl - image.first);
|
||||
PE_SectionHeader *section = pe_section_header_from_name(image_str, name);
|
||||
if (section != 0){
|
||||
result.first = image.first + section->voff;
|
||||
result.opl = result.first + section->vsize;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
#else
|
||||
# error selfimg_get_section not implemented for this OS
|
||||
#endif
|
||||
|
|
@ -0,0 +1,251 @@
|
|||
////////////////////////////////
|
||||
// Context Cracking
|
||||
|
||||
// untangle compiler, os, & architecture
|
||||
#if defined(__clang__)
|
||||
# define COMPILER_CLANG 1
|
||||
|
||||
# if defined(_WIN32)
|
||||
# define OS_WINDOWS 1
|
||||
# elif defined(__gnu_linux__)
|
||||
# define OS_LINUX 1
|
||||
# elif defined(__APPLE__) && defined(__MACH__)
|
||||
# define OS_MAC 1
|
||||
# else
|
||||
# error missing OS detection
|
||||
# endif
|
||||
|
||||
# if defined(__amd64__)
|
||||
# define ARCH_X64 1
|
||||
// TODO(allen): verify this works on clang
|
||||
# elif defined(__i386__)
|
||||
# define ARCH_X86 1
|
||||
// TODO(allen): verify this works on clang
|
||||
# elif defined(__arm__)
|
||||
# define ARCH_ARM 1
|
||||
// TODO(allen): verify this works on clang
|
||||
# elif defined(__aarch64__)
|
||||
# define ARCH_ARM64 1
|
||||
# else
|
||||
# error missing ARCH detection
|
||||
# endif
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
# define COMPILER_CL 1
|
||||
|
||||
# if defined(_WIN32)
|
||||
# define OS_WINDOWS 1
|
||||
# else
|
||||
# error missing OS detection
|
||||
# endif
|
||||
|
||||
# if defined(_M_AMD64)
|
||||
# define ARCH_X64 1
|
||||
# elif defined(_M_I86)
|
||||
# define ARCH_X86 1
|
||||
# elif defined(_M_ARM)
|
||||
# define ARCH_ARM 1
|
||||
// TODO(allen): ARM64?
|
||||
# else
|
||||
# error missing ARCH detection
|
||||
# endif
|
||||
|
||||
#elif defined(__GNUC__)
|
||||
# define COMPILER_GCC 1
|
||||
|
||||
# if defined(_WIN32)
|
||||
# define OS_WINDOWS 1
|
||||
# elif defined(__gnu_linux__)
|
||||
# define OS_LINUX 1
|
||||
# elif defined(__APPLE__) && defined(__MACH__)
|
||||
# define OS_MAC 1
|
||||
# else
|
||||
# error missing OS detection
|
||||
# endif
|
||||
|
||||
# if defined(__amd64__)
|
||||
# define ARCH_X64 1
|
||||
# elif defined(__i386__)
|
||||
# define ARCH_X86 1
|
||||
# elif defined(__arm__)
|
||||
# define ARCH_ARM 1
|
||||
# elif defined(__aarch64__)
|
||||
# define ARCH_ARM64 1
|
||||
# else
|
||||
# error missing ARCH detection
|
||||
# endif
|
||||
|
||||
#else
|
||||
# error no context cracking for this compiler
|
||||
#endif
|
||||
|
||||
#if !defined(COMPILER_CL)
|
||||
# define COMPILER_CL 0
|
||||
#endif
|
||||
#if !defined(COMPILER_CLANG)
|
||||
# define COMPILER_CLANG 0
|
||||
#endif
|
||||
#if !defined(COMPILER_GCC)
|
||||
# define COMPILER_GCC 0
|
||||
#endif
|
||||
#if !defined(OS_WINDOWS)
|
||||
# define OS_WINDOWS 0
|
||||
#endif
|
||||
#if !defined(OS_LINUX)
|
||||
# define OS_LINUX 0
|
||||
#endif
|
||||
#if !defined(OS_MAC)
|
||||
# define OS_MAC 0
|
||||
#endif
|
||||
#if !defined(ARCH_X64)
|
||||
# define ARCH_X64 0
|
||||
#endif
|
||||
#if !defined(ARCH_X86)
|
||||
# define ARCH_X86 0
|
||||
#endif
|
||||
#if !defined(ARCH_ARM)
|
||||
# define ARCH_ARM 0
|
||||
#endif
|
||||
#if !defined(ARCH_ARM64)
|
||||
# define ARCH_ARM64 0
|
||||
#endif
|
||||
|
||||
|
||||
// language
|
||||
#if defined(__cplusplus)
|
||||
# define LANG_CXX 1
|
||||
#else
|
||||
# define LANG_C 1
|
||||
#endif
|
||||
|
||||
#if !defined(LANG_CXX)
|
||||
# define LANG_CXX 0
|
||||
#endif
|
||||
#if !defined(LANG_C)
|
||||
# define LANG_C 0
|
||||
#endif
|
||||
|
||||
|
||||
////////////////////////////////
|
||||
// GLUE(a,b) STRIFY(s)
|
||||
|
||||
#define GLUE__(a,b) a##b
|
||||
#define GLUE_(a,b) GLUE__(a,b)
|
||||
#define GLUE(a,b) GLUE_(a,b)
|
||||
|
||||
#define STRIFY__(s) #s
|
||||
#define STRIFY_(s) STRIFY__(s)
|
||||
#define STRIFY(s) STRIFY_(s)
|
||||
|
||||
|
||||
////////////////////////////////
|
||||
// SECTION(<section-name>) <Decl>
|
||||
|
||||
#if COMPILER_CLANG || COMPILER_GCC
|
||||
# define SECTION(N) __attribute__((__section__(N)))
|
||||
#elif COMPILER_CL
|
||||
# define SECTION(N) __declspec(allocate(N))
|
||||
#else
|
||||
# error SECTION not defined for this compiler
|
||||
#endif
|
||||
|
||||
// for CL users: #pragma section(<section>,read,write)
|
||||
|
||||
|
||||
////////////////////////////////
|
||||
// BEFORE_MAIN(){ <...> }
|
||||
|
||||
#if OS_WINDOWS
|
||||
|
||||
# pragma section(".CRT$XCU", read)
|
||||
|
||||
# if LANG_CXX
|
||||
|
||||
# define BEFORE_MAIN_NAMED(n) \
|
||||
static void n(void); \
|
||||
__declspec(allocate(".CRT$XCU")) \
|
||||
__pragma(comment(linker,"/include:" #n "__")) \
|
||||
extern "C" void (*n##__)(void); \
|
||||
void (*n##__)(void) = n; \
|
||||
static void n(void)
|
||||
|
||||
# else
|
||||
|
||||
# define BEFORE_MAIN_NAMED(n) \
|
||||
static void n(void); \
|
||||
__declspec(allocate(".CRT$XCU")) \
|
||||
__pragma(comment(linker,"/include:" #n "__")) \
|
||||
void (*n##__)(void) = n; \
|
||||
static void n(void)
|
||||
|
||||
# endif
|
||||
|
||||
#elif OS_LINUX
|
||||
|
||||
# define BEFORE_MAIN_NAMED(n) \
|
||||
__attribute__((constructor)) static void n(void)
|
||||
|
||||
#else
|
||||
# error BEFORE_MAIN missing for this OS
|
||||
#endif
|
||||
|
||||
#define BEFORE_MAIN_(n) BEFORE_MAIN_NAMED(n)
|
||||
#define BEFORE_MAIN() BEFORE_MAIN_(GLUE(beforemain,__COUNTER__))
|
||||
|
||||
|
||||
////////////////////////////////
|
||||
// DO_NOT_ELIMINATE
|
||||
|
||||
#if OS_WINDOWS
|
||||
# define DO_NOT_ELIMINATE__S0(N) __pragma(comment(linker,"/include:" #N))
|
||||
# define DO_NOT_ELIMINATE__S1(N) DO_NOT_ELIMINATE__S0(N)
|
||||
# define DO_NOT_ELIMINATE(N) DO_NOT_ELIMINATE__S1(N)
|
||||
#else
|
||||
|
||||
# define DO_NOT_ELIMINATE(N)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
////////////////////////////////
|
||||
// Types
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef int8_t S8;
|
||||
typedef int16_t S16;
|
||||
typedef int32_t S32;
|
||||
typedef int64_t S64;
|
||||
typedef uint8_t U8;
|
||||
typedef uint16_t U16;
|
||||
typedef uint32_t U32;
|
||||
typedef uint64_t U64;
|
||||
typedef S8 B8;
|
||||
typedef S16 B16;
|
||||
typedef S32 B32;
|
||||
typedef S64 B64;
|
||||
typedef float F32;
|
||||
typedef double F64;
|
||||
|
||||
typedef struct RangePtr{
|
||||
U8 *first;
|
||||
U8 *opl;
|
||||
} RangePtr;
|
||||
|
||||
typedef struct String8{
|
||||
U8 *str;
|
||||
U64 size;
|
||||
} String8;
|
||||
|
||||
#define str8_lit(str) str8((U8*)(str), sizeof(str) - 1)
|
||||
#define str8_lit_const(str) { (U8*)(str), sizeof(str) - 1 }
|
||||
#define str8_expand(s) ((int)((s).size)), ((s).str)
|
||||
|
||||
////////////////////////////////
|
||||
// Functions
|
||||
|
||||
static String8 str8(U8 *str, U64 size);
|
||||
static B32 str8_match(String8 a, String8 b, U32 flags);
|
||||
|
||||
static RangePtr os_this_image(void);
|
||||
static RangePtr selfimg_get_section(RangePtr image, String8 name);
|
||||
|
|
@ -0,0 +1,518 @@
|
|||
////////////////////////////////
|
||||
// Functions: ELF
|
||||
|
||||
// normalizing
|
||||
|
||||
MR4TH_SYM_COMPTIME U16
|
||||
elf_u16_decode(void *ptr, B32 flip){
|
||||
U16 result = 0;
|
||||
if (flip){
|
||||
U8 *buf = (U8*)ptr;
|
||||
result = buf[1] | (buf[0] << 8);
|
||||
}
|
||||
else{
|
||||
result = *(U16*)ptr;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME U32
|
||||
elf_u32_decode(void *ptr, B32 flip){
|
||||
U32 result = 0;
|
||||
if (flip){
|
||||
U8 *buf = (U8*)ptr;
|
||||
result = buf[3] | (buf[2] << 8) | (buf[1] << 16) | (buf[0] << 24);
|
||||
}
|
||||
else{
|
||||
result = *(U32*)ptr;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME U64
|
||||
elf_u64_decode(void *ptr, B32 flip){
|
||||
U64 result = 0;
|
||||
if (flip){
|
||||
U8 *buf = (U8*)ptr;
|
||||
result = ((((U64)buf[7]) << 0) | (((U64)buf[6]) << 8) |
|
||||
(((U64)buf[5]) << 16) | (((U64)buf[4]) << 24) |
|
||||
(((U64)buf[3]) << 32) | (((U64)buf[2]) << 40) |
|
||||
(((U64)buf[1]) << 48) | (((U64)buf[0]) << 56));
|
||||
}
|
||||
else{
|
||||
result = *(U64*)ptr;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME void
|
||||
elf_header64_from_header32(ELF_Header64 *dst, ELF_Header32 *src, ELF_Encoding src_encoding){
|
||||
B32 src_big_endian = (src_encoding == ELF_Encoding_2MSB);
|
||||
B32 flip_order = (src_big_endian != ARCH_BIG_ENDIAN);
|
||||
|
||||
MemoryCopyArray(dst->ident, src->ident);
|
||||
dst->type = elf_u16_decode(&src->type, flip_order);
|
||||
dst->machine = elf_u16_decode(&src->machine, flip_order);
|
||||
dst->version = elf_u32_decode(&src->version, flip_order);
|
||||
dst->entry = (U64)elf_u32_decode(&src->entry, flip_order);
|
||||
dst->segment_table_foff = (U64)elf_u32_decode(&src->segment_table_foff, flip_order);
|
||||
dst->section_table_foff = (U64)elf_u32_decode(&src->section_table_foff, flip_order);
|
||||
dst->flags = elf_u32_decode(&src->flags, flip_order);
|
||||
dst->header_size = elf_u16_decode(&src->header_size, flip_order);
|
||||
dst->segment_size = elf_u16_decode(&src->segment_size, flip_order);
|
||||
dst->segment_count = elf_u16_decode(&src->segment_count, flip_order);
|
||||
dst->section_size = elf_u16_decode(&src->section_size, flip_order);
|
||||
dst->section_count = elf_u16_decode(&src->section_count, flip_order);
|
||||
dst->string_section_index = elf_u16_decode(&src->string_section_index, flip_order);
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME void
|
||||
elf_header64_from_header64(ELF_Header64 *dst, ELF_Header64 *src, ELF_Encoding src_encoding){
|
||||
B32 src_big_endian = (src_encoding == ELF_Encoding_2MSB);
|
||||
B32 flip_order = (src_big_endian != ARCH_BIG_ENDIAN);
|
||||
|
||||
if (!flip_order){
|
||||
MemoryCopyStruct(dst, src);
|
||||
}
|
||||
else{
|
||||
MemoryCopyArray(dst->ident, src->ident);
|
||||
dst->type = elf_u16_decode(&src->type, 1);
|
||||
dst->machine = elf_u16_decode(&src->machine, 1);
|
||||
dst->version = elf_u32_decode(&src->version, 1);
|
||||
dst->entry = elf_u32_decode(&src->entry, 1);
|
||||
dst->segment_table_foff = elf_u32_decode(&src->segment_table_foff, 1);
|
||||
dst->section_table_foff = elf_u32_decode(&src->section_table_foff, 1);
|
||||
dst->flags = elf_u32_decode(&src->flags, 1);
|
||||
dst->header_size = elf_u16_decode(&src->header_size, 1);
|
||||
dst->segment_size = elf_u16_decode(&src->segment_size, 1);
|
||||
dst->segment_count = elf_u16_decode(&src->segment_count, 1);
|
||||
dst->section_size = elf_u16_decode(&src->section_size, 1);
|
||||
dst->section_count = elf_u16_decode(&src->section_count, 1);
|
||||
dst->string_section_index = elf_u16_decode(&src->string_section_index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME void
|
||||
elf_section64_from_section32(ELF_Section64 *dst, ELF_Section32 *src, ELF_Encoding src_encoding){
|
||||
B32 src_big_endian = (src_encoding == ELF_Encoding_2MSB);
|
||||
B32 flip_order = (src_big_endian != ARCH_BIG_ENDIAN);
|
||||
|
||||
dst->name = elf_u32_decode(&src->name, flip_order);
|
||||
dst->type = elf_u32_decode(&src->type, flip_order);
|
||||
dst->flags = elf_u32_decode(&src->flags, flip_order);
|
||||
dst->addr = elf_u32_decode(&src->addr, flip_order);
|
||||
dst->offset = elf_u32_decode(&src->offset, flip_order);
|
||||
dst->size = elf_u32_decode(&src->size, flip_order);
|
||||
dst->link = elf_u32_decode(&src->link, flip_order);
|
||||
dst->info = elf_u32_decode(&src->info, flip_order);
|
||||
dst->addralign = elf_u32_decode(&src->addralign, flip_order);
|
||||
dst->entsize = elf_u32_decode(&src->entsize, flip_order);
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME void
|
||||
elf_section64_from_section64(ELF_Section64 *dst, ELF_Section64 *src, ELF_Encoding src_encoding){
|
||||
B32 src_big_endian = (src_encoding == ELF_Encoding_2MSB);
|
||||
B32 flip_order = (src_big_endian != ARCH_BIG_ENDIAN);
|
||||
|
||||
if (!flip_order){
|
||||
MemoryCopyStruct(dst, src);
|
||||
}
|
||||
else{
|
||||
dst->name = elf_u32_decode(&src->name, 1);
|
||||
dst->type = elf_u32_decode(&src->type, 1);
|
||||
dst->flags = elf_u64_decode(&src->flags, 1);
|
||||
dst->addr = elf_u64_decode(&src->addr, 1);
|
||||
dst->offset = elf_u64_decode(&src->offset, 1);
|
||||
dst->size = elf_u64_decode(&src->size, 1);
|
||||
dst->link = elf_u32_decode(&src->link, 1);
|
||||
dst->info = elf_u32_decode(&src->info, 1);
|
||||
dst->addralign = elf_u64_decode(&src->addralign, 1);
|
||||
dst->entsize = elf_u64_decode(&src->entsize, 1);
|
||||
}
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME void
|
||||
elf_segment64_from_segment32(ELF_Segment64 *dst, ELF_Segment32 *src, ELF_Encoding src_encoding){
|
||||
B32 src_big_endian = (src_encoding == ELF_Encoding_2MSB);
|
||||
B32 flip_order = (src_big_endian != ARCH_BIG_ENDIAN);
|
||||
|
||||
dst->type = elf_u32_decode(&src->type, flip_order);
|
||||
dst->offset = elf_u32_decode(&src->offset, flip_order);
|
||||
dst->vaddr = elf_u32_decode(&src->vaddr, flip_order);
|
||||
dst->paddr = elf_u32_decode(&src->paddr, flip_order);
|
||||
dst->file_size = elf_u32_decode(&src->file_size, flip_order);
|
||||
dst->memory_size = elf_u32_decode(&src->memory_size, flip_order);
|
||||
dst->flags = elf_u32_decode(&src->flags, flip_order);
|
||||
dst->align = elf_u32_decode(&src->align, flip_order);
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME void
|
||||
elf_segment64_from_segment64(ELF_Segment64 *dst, ELF_Segment64 *src, ELF_Encoding src_encoding){
|
||||
B32 src_big_endian = (src_encoding == ELF_Encoding_2MSB);
|
||||
B32 flip_order = (src_big_endian != ARCH_BIG_ENDIAN);
|
||||
|
||||
if (!flip_order){
|
||||
MemoryCopyStruct(dst, src);
|
||||
}
|
||||
else{
|
||||
dst->type = elf_u32_decode(&src->type, 1);
|
||||
dst->flags = elf_u32_decode(&src->flags, 1);
|
||||
dst->offset = elf_u64_decode(&src->offset, 1);
|
||||
dst->vaddr = elf_u64_decode(&src->vaddr, 1);
|
||||
dst->paddr = elf_u64_decode(&src->paddr, 1);
|
||||
dst->file_size = elf_u64_decode(&src->file_size, 1);
|
||||
dst->memory_size = elf_u64_decode(&src->memory_size, 1);
|
||||
dst->align = elf_u64_decode(&src->align, 1);
|
||||
}
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME void
|
||||
elf_symbol64_from_symbol32(ELF_Symbol64 *dst, ELF_Symbol32 *src, ELF_Encoding src_encoding){
|
||||
B32 src_big_endian = (src_encoding == ELF_Encoding_2MSB);
|
||||
B32 flip_order = (src_big_endian != ARCH_BIG_ENDIAN);
|
||||
|
||||
dst->name = elf_u32_decode(&src->name, flip_order);
|
||||
dst->value = elf_u32_decode(&src->value, flip_order);
|
||||
dst->size = elf_u32_decode(&src->size, flip_order);
|
||||
dst->info = src->info;
|
||||
dst->other = src->other;
|
||||
dst->section_index = elf_u16_decode(&src->section_index, flip_order);
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME void
|
||||
elf_symbol64_from_symbol64(ELF_Symbol64 *dst, ELF_Symbol64 *src, ELF_Encoding src_encoding){
|
||||
B32 src_big_endian = (src_encoding == ELF_Encoding_2MSB);
|
||||
B32 flip_order = (src_big_endian != ARCH_BIG_ENDIAN);
|
||||
|
||||
if (!flip_order){
|
||||
MemoryCopyStruct(dst, src);
|
||||
}
|
||||
else{
|
||||
dst->name = elf_u32_decode(&src->name, 1);
|
||||
dst->info = src->info;
|
||||
dst->other = src->other;
|
||||
dst->section_index = elf_u16_decode(&src->section_index, 1);
|
||||
dst->value = elf_u64_decode(&src->value, 1);
|
||||
dst->size = elf_u64_decode(&src->size, 1);
|
||||
}
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME ELF_RelocationAdd64*
|
||||
elf_reloca64_from_reloc32(Arena *arena, ELF_Relocation32 *src, U64 count, ELF_Encoding src_encoding){
|
||||
B32 src_big_endian = (src_encoding == ELF_Encoding_2MSB);
|
||||
B32 flip_order = (src_big_endian != ARCH_BIG_ENDIAN);
|
||||
|
||||
ELF_RelocationAdd64 *dst = push_array(arena, ELF_RelocationAdd64, count);
|
||||
{
|
||||
ELF_Relocation32 *srcptr = src;
|
||||
ELF_RelocationAdd64 *dstptr = dst;
|
||||
for (U64 i = 0; i < count; i += 1, srcptr += 1, dstptr += 1){
|
||||
dstptr->offset = elf_u32_decode(&srcptr->offset, flip_order);
|
||||
dstptr->info = elf_u32_decode(&srcptr->info, flip_order);
|
||||
}
|
||||
}
|
||||
|
||||
return(dst);
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME ELF_RelocationAdd64*
|
||||
elf_reloca64_from_reloc64(Arena *arena, ELF_Relocation64 *src, U64 count, ELF_Encoding src_encoding){
|
||||
B32 src_big_endian = (src_encoding == ELF_Encoding_2MSB);
|
||||
B32 flip_order = (src_big_endian != ARCH_BIG_ENDIAN);
|
||||
|
||||
ELF_RelocationAdd64 *dst = push_array(arena, ELF_RelocationAdd64, count);
|
||||
{
|
||||
ELF_Relocation64 *srcptr = src;
|
||||
ELF_RelocationAdd64 *dstptr = dst;
|
||||
for (U64 i = 0; i < count; i += 1, srcptr += 1, dstptr += 1){
|
||||
dstptr->offset = elf_u64_decode(&srcptr->offset, flip_order);
|
||||
dstptr->info = elf_u64_decode(&srcptr->info, flip_order);
|
||||
}
|
||||
}
|
||||
|
||||
return(dst);
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME ELF_RelocationAdd64*
|
||||
elf_reloca64_from_reloca32(Arena *arena, ELF_RelocationAdd32 *src, U64 count, ELF_Encoding src_encoding){
|
||||
B32 src_big_endian = (src_encoding == ELF_Encoding_2MSB);
|
||||
B32 flip_order = (src_big_endian != ARCH_BIG_ENDIAN);
|
||||
|
||||
ELF_RelocationAdd64 *dst = push_array(arena, ELF_RelocationAdd64, count);
|
||||
{
|
||||
ELF_RelocationAdd32 *srcptr = src;
|
||||
ELF_RelocationAdd64 *dstptr = dst;
|
||||
for (U64 i = 0; i < count; i += 1, srcptr += 1, dstptr += 1){
|
||||
dstptr->offset = elf_u32_decode(&srcptr->offset, flip_order);
|
||||
dstptr->info = elf_u32_decode(&srcptr->info, flip_order);
|
||||
dstptr->addend = (S32)elf_u32_decode(&srcptr->addend, flip_order);
|
||||
}
|
||||
}
|
||||
|
||||
return(dst);
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME ELF_RelocationAdd64*
|
||||
elf_reloca64_from_reloca64(Arena *arena, ELF_RelocationAdd64 *src, U64 count, ELF_Encoding src_encoding){
|
||||
B32 src_big_endian = (src_encoding == ELF_Encoding_2MSB);
|
||||
B32 flip_order = (src_big_endian != ARCH_BIG_ENDIAN);
|
||||
|
||||
ELF_RelocationAdd64 *dst = push_array(arena, ELF_RelocationAdd64, count);
|
||||
{
|
||||
ELF_RelocationAdd64 *srcptr = src;
|
||||
ELF_RelocationAdd64 *dstptr = dst;
|
||||
for (U64 i = 0; i < count; i += 1, srcptr += 1, dstptr += 1){
|
||||
dstptr->offset = elf_u64_decode(&srcptr->offset, flip_order);
|
||||
dstptr->info = elf_u64_decode(&srcptr->info, flip_order);
|
||||
dstptr->addend = (S64)elf_u64_decode(&srcptr->addend, flip_order);
|
||||
}
|
||||
}
|
||||
|
||||
return(dst);
|
||||
}
|
||||
|
||||
// strings
|
||||
|
||||
MR4TH_SYM_COMPTIME String8
|
||||
elf_str8_from_identification_idx(ELF_IdentificationIdx idx){
|
||||
String8 result = str8_lit("ERROR");
|
||||
switch (idx){
|
||||
#define X(N,C) case C: result = str8_lit(#N); break;
|
||||
ELF_IdentificationIdx_XList(X)
|
||||
#undef X
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME String8
|
||||
elf_str8_from_class(ELF_Class elf_class){
|
||||
String8 result = str8_lit("ERROR");
|
||||
switch (elf_class){
|
||||
#define X(N,C) case C: result = str8_lit(#N); break;
|
||||
ELF_Class_XList(X)
|
||||
#undef X
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME String8
|
||||
elf_str8_from_encoding(ELF_Encoding elf_encoding){
|
||||
String8 result = str8_lit("ERROR");
|
||||
switch (elf_encoding){
|
||||
#define X(N,C) case C: result = str8_lit(#N); break;
|
||||
ELF_Encoding_XList(X)
|
||||
#undef X
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME String8
|
||||
elf_str8_from_osabi(ELF_OsAbiExtension elf_osabi){
|
||||
String8 result = str8_lit("ERROR");
|
||||
switch (elf_osabi){
|
||||
#define X(N,C) case C: result = str8_lit(#N); break;
|
||||
ELF_OsAbiExtension_XList(X)
|
||||
#undef X
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME String8
|
||||
elf_str8_from_file_type(ELF_FileType file_type){
|
||||
String8 result = str8_lit("ERROR");
|
||||
switch (file_type){
|
||||
#define X(N,C) case C: result = str8_lit(#N); break;
|
||||
ELF_FileType_XList(X)
|
||||
#undef X
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME String8
|
||||
elf_str8_from_machine_type(ELF_FileType machine_type){
|
||||
String8 result = str8_lit("ERROR");
|
||||
switch (machine_type){
|
||||
#define X(N,C) case C: result = str8_lit(#N); break;
|
||||
ELF_MachineType_XList(X)
|
||||
#undef X
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME String8
|
||||
elf_str8_from_section_type(ELF_SectionType section_type){
|
||||
String8 result = str8_lit("ERROR");
|
||||
|
||||
if (ELF_SectionType_LOOS <= section_type &&
|
||||
section_type <= ELF_SectionType_HIOS){
|
||||
result = str8_lit("OS-CUSTOM-TYPE");
|
||||
}
|
||||
|
||||
else if (ELF_SectionType_LOPROC <= section_type &&
|
||||
section_type <= ELF_SectionType_HIPROC){
|
||||
result = str8_lit("PROC-CUSTOM-TYPE");
|
||||
}
|
||||
|
||||
else if (ELF_SectionType_LOUSER <= section_type &&
|
||||
section_type <= ELF_SectionType_HIUSER){
|
||||
result = str8_lit("USER-CUSTOM-TYPE");
|
||||
}
|
||||
|
||||
else{
|
||||
switch (section_type){
|
||||
#define X(N,C) case C: result = str8_lit(#N); break;
|
||||
ELF_SectionType_XList(X)
|
||||
#undef X
|
||||
}
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME void
|
||||
elf_str8list_from_section_flags(Arena *arena, String8List *out, U32 flags){
|
||||
U32 f = 1;
|
||||
for (U32 i = 0; i < 20; i += 1){
|
||||
if ((flags & f) != 0){
|
||||
switch (f){
|
||||
#define X(N,C) case C: str8_list_push(arena, out, str8_lit(#N)); break;
|
||||
ELF_SectionFlags_XList(X)
|
||||
#undef X
|
||||
}
|
||||
}
|
||||
f <<= 1;
|
||||
}
|
||||
if ((flags & ELF_SectionFlag_MASKOS) != 0){
|
||||
str8_list_pushf(arena, out, "OS-CUSTOM(%02x)", (flags >> 20)&0xFF);
|
||||
}
|
||||
if ((flags & ELF_SectionFlag_MASKPROC) != 0){
|
||||
str8_list_pushf(arena, out, "PROC-CUSTOM(%01x)", (flags >> 28)&0xF);
|
||||
}
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME String8
|
||||
elf_str8_from_section_flags(Arena *arena, U32 flags){
|
||||
ArenaTemp scratch = arena_get_scratch(&arena, 1);
|
||||
String8List list = {0};
|
||||
elf_str8list_from_section_flags(scratch.arena, &list, flags);
|
||||
String8 result = str8_join_flags(arena, &list);
|
||||
arena_release_scratch(&scratch);
|
||||
return(result);
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME String8
|
||||
elf_str8_from_segment_type(ELF_SegmentType segment_type){
|
||||
String8 result = str8_lit("ERROR");
|
||||
|
||||
if (ELF_SegmentType_LOOS <= segment_type &&
|
||||
segment_type <= ELF_SegmentType_HIOS){
|
||||
result = str8_lit("OS-CUSTOM-TYPE");
|
||||
}
|
||||
|
||||
else if (ELF_SegmentType_LOPROC <= segment_type &&
|
||||
segment_type <= ELF_SegmentType_HIPROC){
|
||||
result = str8_lit("PROC-CUSTOM-TYPE");
|
||||
}
|
||||
|
||||
else{
|
||||
switch (segment_type){
|
||||
#define X(N,C) case C: result = str8_lit(#N); break;
|
||||
ELF_SegmentType_XList(X)
|
||||
#undef X
|
||||
}
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME void
|
||||
elf_str8list_from_segment_flags(Arena *arena, String8List *out, ELF_SegmentFlags flags){
|
||||
U32 f = 1;
|
||||
for (U32 i = 0; i < 20; i += 1){
|
||||
if ((flags & f) != 0){
|
||||
switch (f){
|
||||
#define X(N,C) case C: str8_list_push(arena, out, str8_lit(#N)); break;
|
||||
ELF_SegmentFlags_XList(X)
|
||||
#undef X
|
||||
}
|
||||
}
|
||||
f <<= 1;
|
||||
}
|
||||
if ((flags & ELF_SegmentFlag_MASKOS) != 0){
|
||||
str8_list_pushf(arena, out, "OS-CUSTOM(%02x)", (flags >> 20)&0xFF);
|
||||
}
|
||||
if ((flags & ELF_SegmentFlag_MASKPROC) != 0){
|
||||
str8_list_pushf(arena, out, "PROC-CUSTOM(%01x)", (flags >> 28)&0xF);
|
||||
}
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME String8
|
||||
elf_str8_from_segment_flags(Arena *arena, ELF_SegmentFlags flags){
|
||||
ArenaTemp scratch = arena_get_scratch(&arena, 1);
|
||||
String8List list = {0};
|
||||
elf_str8list_from_segment_flags(scratch.arena, &list, flags);
|
||||
String8 result = str8_join_flags(arena, &list);
|
||||
arena_release_scratch(&scratch);
|
||||
return(result);
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME String8
|
||||
elf_str8_from_symbol_binding(ELF_SymbolBinding bind){
|
||||
String8 result = str8_lit("ERROR");
|
||||
|
||||
if (ELF_SymbolBinding_LOOS <= bind &&
|
||||
bind <= ELF_SymbolBinding_HIOS){
|
||||
result = str8_lit("OS-CUSTOM-TYPE");
|
||||
}
|
||||
|
||||
else if (ELF_SymbolBinding_LOPROC <= bind &&
|
||||
bind <= ELF_SymbolBinding_HIPROC){
|
||||
result = str8_lit("PROC-CUSTOM-TYPE");
|
||||
}
|
||||
|
||||
else{
|
||||
switch (bind){
|
||||
#define X(N,C) case C: result = str8_lit(#N); break;
|
||||
ELF_SymbolBinding_XList(X)
|
||||
#undef X
|
||||
}
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME String8
|
||||
elf_str8_from_symbol_type(ELF_SymbolType type){
|
||||
String8 result = str8_lit("ERROR");
|
||||
|
||||
if (ELF_SymbolType_LOOS <= type &&
|
||||
type <= ELF_SymbolType_HIOS){
|
||||
result = str8_lit("OS-CUSTOM-TYPE");
|
||||
}
|
||||
|
||||
else if (ELF_SymbolType_LOPROC <= type &&
|
||||
type <= ELF_SymbolType_HIPROC){
|
||||
result = str8_lit("PROC-CUSTOM-TYPE");
|
||||
}
|
||||
|
||||
else{
|
||||
switch (type){
|
||||
#define X(N,C) case C: result = str8_lit(#N); break;
|
||||
ELF_SymbolType_XList(X)
|
||||
#undef X
|
||||
}
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME String8
|
||||
elf_str8_from_symbol_vis(ELF_SymbolVis vis){
|
||||
String8 result = str8_lit("ERROR");
|
||||
switch (vis){
|
||||
#define X(N,C) case C: result = str8_lit(#N); break;
|
||||
ELF_SymbolVis_XList(X)
|
||||
#undef X
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
|
@ -0,0 +1,567 @@
|
|||
/*
|
||||
** ELF File Dumper
|
||||
*/
|
||||
|
||||
|
||||
#include "mr4th_base.h"
|
||||
#include "mr4th_base.stdio.h"
|
||||
#include "mr4th_keywords.h"
|
||||
|
||||
#include "mr4th_elf.h"
|
||||
|
||||
#include "mr4th_elf.dump.h"
|
||||
|
||||
#include "mr4th_base.c"
|
||||
#include "mr4th_elf.c"
|
||||
|
||||
////////////////////////////////
|
||||
// ELF DUMP Arguments Functions
|
||||
|
||||
function ELFDUMP_Arguments*
|
||||
elfdump_args(Arena *arena, String8List *command_line_args){
|
||||
// parse
|
||||
CMDLN *cmdln = cmdln_from_args(arena, command_line_args);
|
||||
|
||||
// setup args
|
||||
ELFDUMP_Arguments *args = push_array(arena, ELFDUMP_Arguments, 1);
|
||||
|
||||
// get input file name
|
||||
args->input_file_name = cmdln_input_from_idx(cmdln, 0);
|
||||
|
||||
return(args);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
// Entry Point
|
||||
|
||||
int main(int argc, char **argv){
|
||||
os_main_init(argc, argv);
|
||||
|
||||
Arena *arena = arena_alloc();
|
||||
|
||||
// arguments
|
||||
String8List command_line_args = os_command_line_arguments();
|
||||
ELFDUMP_Arguments *args = elfdump_args(arena, &command_line_args);
|
||||
|
||||
// load input file
|
||||
String8 input_data = os_file_read(arena, args->input_file_name);
|
||||
|
||||
|
||||
/////////////////
|
||||
///// PARSE /////
|
||||
/////////////////
|
||||
|
||||
// magic check
|
||||
B32 elf_magic = 0;
|
||||
ELF_Class elf_class = ELF_Class_NONE;
|
||||
ELF_Encoding elf_encoding = ELF_Encoding_NONE;
|
||||
U32 elf_version = 0;
|
||||
ELF_OsAbiExtension elf_ext = ELF_OsAbiExtension_NONE;
|
||||
|
||||
if (input_data.size >= ELF_NUM_IDENT){
|
||||
if (input_data.str[0] == ELF_Magic_Byte0 &&
|
||||
input_data.str[1] == ELF_Magic_Byte1 &&
|
||||
input_data.str[2] == ELF_Magic_Byte2 &&
|
||||
input_data.str[3] == ELF_Magic_Byte3){
|
||||
elf_magic = 1;
|
||||
}
|
||||
elf_class = input_data.str[ELF_IdentificationIdx_CLASS];
|
||||
elf_encoding = input_data.str[ELF_IdentificationIdx_DATA];
|
||||
elf_version = input_data.str[ELF_IdentificationIdx_VERSION];
|
||||
elf_ext = input_data.str[ELF_IdentificationIdx_OSABI];
|
||||
}
|
||||
|
||||
B32 elf_header_good = 1;
|
||||
if (!elf_magic || elf_class == 0 || elf_encoding == 0 || elf_version != 1){
|
||||
elf_header_good = 0;
|
||||
}
|
||||
|
||||
// elf header
|
||||
ELF_Header32 *hdr32_raw = 0;
|
||||
ELF_Header64 *hdr64_raw = 0;
|
||||
if (elf_header_good){
|
||||
|
||||
// 32-bit
|
||||
if (elf_class == ELF_Class_32){
|
||||
if (sizeof(*hdr32_raw) <= input_data.size){
|
||||
hdr32_raw = (ELF_Header32*)input_data.str;
|
||||
}
|
||||
}
|
||||
|
||||
// 64-bit
|
||||
if (elf_class == ELF_Class_64){
|
||||
if (sizeof(*hdr64_raw) <= input_data.size){
|
||||
hdr64_raw = (ELF_Header64*)input_data.str;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// normalize header
|
||||
ELF_Header64 hdr = {0};
|
||||
if (hdr32_raw != 0){
|
||||
elf_header64_from_header32(&hdr, hdr32_raw, elf_encoding);
|
||||
}
|
||||
else if (hdr64_raw != 0){
|
||||
elf_header64_from_header64(&hdr, hdr64_raw, elf_encoding);
|
||||
}
|
||||
else{
|
||||
elf_header_good = 0;
|
||||
}
|
||||
|
||||
// sections
|
||||
ELF_Section32 *sec32_raw = 0;
|
||||
ELF_Section64 *sec64_raw = 0;
|
||||
if (elf_header_good){
|
||||
|
||||
U64 foff = hdr.section_table_foff;
|
||||
U64 opl_foff = foff + hdr.section_count*hdr.section_size;
|
||||
|
||||
if (opl_foff <= input_data.size){
|
||||
// 32-bit
|
||||
if (elf_class == ELF_Class_32){
|
||||
sec32_raw = (ELF_Section32*)(input_data.str + foff);
|
||||
}
|
||||
|
||||
// 64-bit
|
||||
if (elf_class == ELF_Class_64){
|
||||
sec64_raw = (ELF_Section64*)(input_data.str + foff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// normalize sections
|
||||
B32 sections_good = 1;
|
||||
ELF_Section64 *sections = 0;
|
||||
if (sec32_raw != 0){
|
||||
sections = push_array(arena, ELF_Section64, hdr.section_count);
|
||||
for (U32 i = 0; i < hdr.section_count; i += 1){
|
||||
elf_section64_from_section32(sections + i, sec32_raw + i, elf_encoding);
|
||||
}
|
||||
}
|
||||
else if (sec64_raw != 0){
|
||||
sections = push_array(arena, ELF_Section64, hdr.section_count);
|
||||
for (U32 i = 0; i < hdr.section_count; i += 1){
|
||||
elf_section64_from_section64(sections + i, sec64_raw + i, elf_encoding);
|
||||
}
|
||||
}
|
||||
else{
|
||||
sections_good = 0;
|
||||
}
|
||||
|
||||
// segments
|
||||
ELF_Segment32 *seg32_raw = 0;
|
||||
ELF_Segment64 *seg64_raw = 0;
|
||||
if (elf_header_good){
|
||||
|
||||
U64 foff = hdr.segment_table_foff;
|
||||
U64 opl_foff = foff + hdr.segment_count*hdr.segment_size;
|
||||
|
||||
if (opl_foff <= input_data.size){
|
||||
// 32-bit
|
||||
if (elf_class == ELF_Class_32){
|
||||
seg32_raw = (ELF_Segment32*)(input_data.str + foff);
|
||||
}
|
||||
|
||||
// 64-bit
|
||||
if (elf_class == ELF_Class_64){
|
||||
seg64_raw = (ELF_Segment64*)(input_data.str + foff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// normalize segments
|
||||
B32 segments_good = 1;
|
||||
ELF_Segment64 *segments = 0;
|
||||
if (seg32_raw != 0){
|
||||
segments = push_array(arena, ELF_Segment64, hdr.segment_count);
|
||||
for (U32 i = 0; i < hdr.segment_count; i += 1){
|
||||
elf_segment64_from_segment32(segments + i, seg32_raw + i, elf_encoding);
|
||||
}
|
||||
}
|
||||
else if (seg64_raw != 0){
|
||||
segments = push_array(arena, ELF_Segment64, hdr.segment_count);
|
||||
for (U32 i = 0; i < hdr.segment_count; i += 1){
|
||||
elf_segment64_from_segment64(segments + i, seg64_raw + i, elf_encoding);
|
||||
}
|
||||
}
|
||||
else{
|
||||
segments_good = 0;
|
||||
}
|
||||
|
||||
// find symtab section
|
||||
ELF_Section64 *symtab_section = 0;
|
||||
for (U32 i = 0; i < hdr.section_count; i += 1){
|
||||
ELF_Section64 *section = sections + i;
|
||||
if (section->type == ELF_SectionType_SYMTAB){
|
||||
symtab_section = section;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// find dynsym section
|
||||
ELF_Section64 *dynsym_section = 0;
|
||||
for (U32 i = 0; i < hdr.section_count; i += 1){
|
||||
ELF_Section64 *section = sections + i;
|
||||
if (section->type == ELF_SectionType_DYNSYM){
|
||||
dynsym_section = section;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// decode symol tables
|
||||
ELFDUMP_SymbolTable symbol_tables[2] = {0};
|
||||
|
||||
ELF_Section64 *symbol_table_sections[2];
|
||||
symbol_table_sections[0] = symtab_section;
|
||||
symbol_table_sections[1] = dynsym_section;
|
||||
|
||||
for (U32 k = 0; k < 2; k += 1){
|
||||
ELF_Section64 *symbol_section = symbol_table_sections[k];
|
||||
|
||||
ELF_Symbol32 *sym32_raw = 0;
|
||||
ELF_Symbol64 *sym64_raw = 0;
|
||||
U8 *string_table_first = 0;
|
||||
U8 *string_table_opl = 0;
|
||||
U32 symbol_count = 0;
|
||||
|
||||
if (symbol_section != 0){
|
||||
|
||||
// extract symbol string table
|
||||
if (symbol_section->link < hdr.section_count){
|
||||
ELF_Section64 *string_table = sections + symbol_section->link;
|
||||
string_table_first = input_data.str + string_table->offset;
|
||||
string_table_opl = string_table_first + string_table->size;
|
||||
}
|
||||
|
||||
// extract raw symbol array
|
||||
U64 foff = symbol_section->offset;
|
||||
U64 opl_foff = foff + symbol_section->size;
|
||||
|
||||
U64 symbol_count_cap = 0;
|
||||
|
||||
if (opl_foff <= input_data.size){
|
||||
// 32-bit
|
||||
if (elf_class == ELF_Class_32){
|
||||
sym32_raw = (ELF_Symbol32*)(input_data.str + foff);
|
||||
symbol_count_cap = symbol_section->size/sizeof(*sym32_raw);
|
||||
}
|
||||
|
||||
// 64-bit
|
||||
if (elf_class == ELF_Class_64){
|
||||
sym64_raw = (ELF_Symbol64*)(input_data.str + foff);
|
||||
symbol_count_cap = symbol_section->size/sizeof(*sym64_raw);
|
||||
}
|
||||
}
|
||||
|
||||
// extract symbol count
|
||||
symbol_count = symbol_section->info;
|
||||
symbol_count = ClampTop(symbol_count, symbol_count_cap);
|
||||
}
|
||||
|
||||
// normalize symbol table
|
||||
ELF_Symbol64 *symbols = 0;
|
||||
if (sym32_raw != 0){
|
||||
symbols = push_array(arena, ELF_Symbol64, symbol_count);
|
||||
for (U32 i = 0; i < symbol_count; i += 1){
|
||||
elf_symbol64_from_symbol32(symbols + i, sym32_raw + i, elf_encoding);
|
||||
}
|
||||
}
|
||||
else if (sym64_raw != 0){
|
||||
symbols = push_array(arena, ELF_Symbol64, symbol_count);
|
||||
for (U32 i = 0; i < symbol_count; i += 1){
|
||||
elf_symbol64_from_symbol64(symbols + i, sym64_raw + i, elf_encoding);
|
||||
}
|
||||
}
|
||||
|
||||
// fill symbol table
|
||||
if (symbols != 0){
|
||||
ELFDUMP_SymbolTable *symbol_table = &symbol_tables[k];
|
||||
symbol_table->symbols = symbols;
|
||||
symbol_table->count = symbol_count;
|
||||
symbol_table->string_table_first = string_table_first;
|
||||
symbol_table->string_table_opl = string_table_opl;
|
||||
}
|
||||
}
|
||||
|
||||
// relocations
|
||||
ELFDUMP_Relocs *first_relocs = 0;
|
||||
ELFDUMP_Relocs *last_relocs = 0;
|
||||
|
||||
if (sections_good){
|
||||
for (U32 i = 0; i < hdr.section_count; i += 1){
|
||||
|
||||
ELF_RelocationAdd64 *relocs = 0;
|
||||
U64 reloc_count = 0;
|
||||
|
||||
ELF_Section64 *section = sections + i;
|
||||
void *section_data = input_data.str + section->offset;
|
||||
|
||||
switch (section->type){
|
||||
case ELF_SectionType_REL:
|
||||
{
|
||||
if (elf_class == ELF_Class_32){
|
||||
ELF_Relocation32 *reloc32 = (ELF_Relocation32*)section_data;
|
||||
reloc_count = section->size/sizeof(*reloc32);
|
||||
relocs = elf_reloca64_from_reloc32(arena, reloc32, reloc_count, elf_encoding);
|
||||
}
|
||||
else{
|
||||
ELF_Relocation64 *reloc64 = (ELF_Relocation64*)section_data;
|
||||
reloc_count = section->size/sizeof(*reloc64);
|
||||
relocs = elf_reloca64_from_reloc64(arena, reloc64, reloc_count, elf_encoding);
|
||||
}
|
||||
}break;
|
||||
|
||||
case ELF_SectionType_RELA:
|
||||
{
|
||||
if (elf_class == ELF_Class_32){
|
||||
ELF_RelocationAdd32 *reloca32 = (ELF_RelocationAdd32*)section_data;
|
||||
reloc_count = section->size/sizeof(*reloca32);
|
||||
relocs = elf_reloca64_from_reloca32(arena, reloca32, reloc_count, elf_encoding);
|
||||
}
|
||||
else{
|
||||
ELF_RelocationAdd64 *reloca64 = (ELF_RelocationAdd64*)section_data;
|
||||
reloc_count = section->size/sizeof(*reloca64);
|
||||
relocs = elf_reloca64_from_reloca64(arena, reloca64, reloc_count, elf_encoding);
|
||||
}
|
||||
}break;
|
||||
}
|
||||
|
||||
if (reloc_count > 0){
|
||||
ELFDUMP_Relocs *r = push_array(arena, ELFDUMP_Relocs, 1);
|
||||
SLLQueuePush(first_relocs, last_relocs, r);
|
||||
r->section_idx = i;
|
||||
r->symbol_table_section_idx = section->link;
|
||||
r->target_section_idx = section->info;
|
||||
r->relocs = relocs;
|
||||
r->count = reloc_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////
|
||||
///// DUMP /////
|
||||
////////////////
|
||||
|
||||
if (!elf_header_good){
|
||||
m4_printf("Unsuccessful parse\n");
|
||||
}
|
||||
|
||||
if (elf_header_good){
|
||||
ArenaTemp scratch = arena_get_scratch(0, 0);
|
||||
|
||||
// elf header
|
||||
{
|
||||
|
||||
for (U32 i = 0; i < ELF_NUM_IDENT; i += 1){
|
||||
String8 ident_string = elf_str8_from_identification_idx(i);
|
||||
|
||||
String8 val_string = {0};
|
||||
switch (i){
|
||||
case ELF_IdentificationIdx_CLASS:
|
||||
{
|
||||
val_string = elf_str8_from_class(hdr.ident[i]);
|
||||
}break;
|
||||
|
||||
case ELF_IdentificationIdx_DATA:
|
||||
{
|
||||
val_string = elf_str8_from_encoding(hdr.ident[i]);
|
||||
}break;
|
||||
|
||||
case ELF_IdentificationIdx_OSABI:
|
||||
{
|
||||
val_string = elf_str8_from_osabi(hdr.ident[i]);
|
||||
}break;
|
||||
|
||||
default:
|
||||
{
|
||||
val_string = str8_pushf(scratch.arena, "0x%02x", hdr.ident[i]);
|
||||
}break;
|
||||
}
|
||||
|
||||
m4_printf("elf_header.ident[%10S] = %S\n", &ident_string, &val_string);
|
||||
}
|
||||
|
||||
String8 type_string = elf_str8_from_file_type(hdr.type);
|
||||
String8 machine_string = elf_str8_from_machine_type(hdr.machine);
|
||||
|
||||
m4_printf("elf_header.type = %S\n", &type_string);
|
||||
m4_printf("elf_header.machine = %S\n", &machine_string);
|
||||
m4_printf("elf_header.version = %u\n", hdr.version);
|
||||
m4_printf("elf_header.entry = 0x%08llx\n", hdr.entry);
|
||||
m4_printf("elf_header.segment_table_foff = 0x%08llx\n", hdr.segment_table_foff);
|
||||
m4_printf("elf_header.section_table_foff = 0x%08llx\n", hdr.section_table_foff);
|
||||
// TODO(allen): flags pneumonics
|
||||
m4_printf("elf_header.flags = 0x%08x\n", hdr.flags);
|
||||
m4_printf("elf_header.header_size = %u\n", hdr.header_size);
|
||||
m4_printf("elf_header.segment_size = %u\n", hdr.segment_size);
|
||||
m4_printf("elf_header.segment_count = %u\n", hdr.segment_count);
|
||||
m4_printf("elf_header.section_size = %u\n", hdr.section_size);
|
||||
m4_printf("elf_header.section_count = %u\n", hdr.section_count);
|
||||
m4_printf("elf_header.string_section_index = %u\n", hdr.string_section_index);
|
||||
|
||||
m4_printf("\n");
|
||||
|
||||
arena_release_scratch(&scratch);
|
||||
}
|
||||
|
||||
// sections
|
||||
if (sections_good){
|
||||
|
||||
// get the section name string table
|
||||
U8 *string_table_first = 0;
|
||||
U8 *string_table_opl = 0;
|
||||
{
|
||||
ELF_Section64 *string_table = 0;
|
||||
if (hdr.string_section_index != ELF_SectionIndex_UNDEF &&
|
||||
hdr.string_section_index != ELF_SectionIndex_XINDEX){
|
||||
string_table = sections + hdr.string_section_index;
|
||||
}
|
||||
else if (hdr.string_section_index == ELF_SectionIndex_XINDEX){
|
||||
U32 string_section_index = sections[0].link;
|
||||
string_table = sections + string_section_index;
|
||||
}
|
||||
|
||||
if (string_table != 0){
|
||||
string_table_first = input_data.str + string_table->offset;
|
||||
string_table_opl = string_table_first + string_table->size;
|
||||
}
|
||||
}
|
||||
|
||||
// dump each section
|
||||
for (U32 i = 0; i < hdr.section_count; i += 1){
|
||||
ELF_Section64 *section = sections + i;
|
||||
|
||||
String8 name = str8_cstring_capped(string_table_first + section->name,
|
||||
string_table_opl);
|
||||
String8 type_string = elf_str8_from_section_type(section->type);
|
||||
String8 flags_string =
|
||||
elf_str8_from_section_flags(scratch.arena, section->flags);
|
||||
|
||||
m4_printf("section[%u] = {\n"
|
||||
" name = \"%S\",\n"
|
||||
" type = %S (0x%x),\n"
|
||||
" flags = %S,\n"
|
||||
" addr = 0x%08llx,\n"
|
||||
" size = %$llu,\n"
|
||||
" link = %u,\n"
|
||||
" info = %u,\n"
|
||||
" addralign = %llu,\n"
|
||||
" entsize = %$llu,\n"
|
||||
"}\n",
|
||||
i, &name,
|
||||
&type_string, section->type,
|
||||
&flags_string,
|
||||
section->addr,
|
||||
section->size,
|
||||
section->link,
|
||||
section->info,
|
||||
section->addralign,
|
||||
section->entsize);
|
||||
|
||||
}
|
||||
|
||||
m4_printf("\n");
|
||||
|
||||
}
|
||||
|
||||
// segments
|
||||
if (segments_good){
|
||||
for (U32 i = 0; i < hdr.segment_count; i += 1){
|
||||
ELF_Segment64 *segment = segments + i;
|
||||
|
||||
String8 type_string = elf_str8_from_segment_type(segment->type);
|
||||
String8 flags_string =
|
||||
elf_str8_from_segment_flags(scratch.arena, segment->flags);
|
||||
|
||||
m4_printf("segment[%u] = {\n"
|
||||
" type = %S (0x%x),\n"
|
||||
" flags = %S,\n"
|
||||
" offset = 0x%08llx,\n"
|
||||
" vaddr = 0x%08llx,\n"
|
||||
" paddr = 0x%08llx,\n"
|
||||
" file_size = %$llu,\n"
|
||||
" memory_size = %$llu,\n"
|
||||
" align = %llu,\n"
|
||||
"}\n",
|
||||
i,
|
||||
&type_string, segment->type,
|
||||
&flags_string,
|
||||
segment->offset,
|
||||
segment->vaddr,
|
||||
segment->paddr,
|
||||
segment->file_size,
|
||||
segment->memory_size,
|
||||
segment->align);
|
||||
}
|
||||
|
||||
m4_printf("\n");
|
||||
}
|
||||
|
||||
// symbol tables
|
||||
String8 symbol_table_name[2];
|
||||
symbol_table_name[0] = str8_lit("symtab");
|
||||
symbol_table_name[1] = str8_lit("dynsym");
|
||||
|
||||
for (U32 k = 0; k < 2; k += 1){
|
||||
ELFDUMP_SymbolTable *symbol_table = &symbol_tables[k];
|
||||
|
||||
if (symbol_table->symbols != 0){
|
||||
for (U32 i = 0; i < symbol_table->count; i += 1){
|
||||
ELF_Symbol64 *symbol = symbol_table->symbols + i;
|
||||
|
||||
String8 name =
|
||||
str8_cstring_capped(symbol_table->string_table_first + symbol->name,
|
||||
symbol_table->string_table_opl);
|
||||
|
||||
ELF_SymbolBinding bind = ELF_Symbol_BindFromInfo(symbol->info);
|
||||
ELF_SymbolType type = ELF_Symbol_TypeFromInfo(symbol->info);
|
||||
|
||||
ELF_SymbolVis vis = ELF_Symbol_VisFromOther(symbol->other);
|
||||
|
||||
String8 bind_string = elf_str8_from_symbol_binding(bind);
|
||||
String8 type_string = elf_str8_from_symbol_type(type);
|
||||
String8 vis_string = elf_str8_from_symbol_vis(vis);
|
||||
|
||||
m4_printf("%S[%u] = {\n"
|
||||
" name = \"%S\",\n"
|
||||
" info = bind: %S, type: %S,\n"
|
||||
" other = vis: %S,\n"
|
||||
" section_index = %u,\n"
|
||||
" value = %llu,\n"
|
||||
" size = %$llu,\n"
|
||||
"}\n",
|
||||
&symbol_table_name[k], i,
|
||||
&name,
|
||||
&bind_string, &type_string,
|
||||
&vis_string,
|
||||
symbol->section_index,
|
||||
symbol->value,
|
||||
symbol->size);
|
||||
}
|
||||
|
||||
m4_printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
// relocations
|
||||
for (ELFDUMP_Relocs *relocs = first_relocs;
|
||||
relocs != 0;
|
||||
relocs = relocs->next){
|
||||
m4_printf("relocations(%u) = {\n", relocs->section_idx);
|
||||
|
||||
U32 count = relocs->count;
|
||||
ELF_RelocationAdd64 *relocptr = relocs->relocs;
|
||||
for (U32 i = 0; i < count; i += 1, relocptr += 1){
|
||||
m4_printf(" { offset = %llu,\n"
|
||||
" info = %llu,\n"
|
||||
" addend = %lld,\n"
|
||||
" },\n", relocptr->offset, relocptr->info, relocptr->addend);
|
||||
}
|
||||
|
||||
m4_printf("}\n\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
#ifndef MR4TH_ELF_DUMP_H
|
||||
#define MR4TH_ELF_DUMP_H
|
||||
|
||||
////////////////////////////////
|
||||
// ELF DUMP Arguments Types
|
||||
|
||||
typedef struct ELFDUMP_Arguments{
|
||||
String8 input_file_name;
|
||||
} ELFDUMP_Arguments;
|
||||
|
||||
////////////////////////////////
|
||||
// ELF DUMP Types
|
||||
|
||||
typedef struct ELFDUMP_SymbolTable{
|
||||
ELF_Symbol64 *symbols;
|
||||
U32 count;
|
||||
U8 *string_table_first;
|
||||
U8 *string_table_opl;
|
||||
} ELFDUMP_SymbolTable;
|
||||
|
||||
typedef struct ELFDUMP_Relocs{
|
||||
struct ELFDUMP_Relocs *next;
|
||||
U32 section_idx;
|
||||
U32 symbol_table_section_idx;
|
||||
U32 target_section_idx;
|
||||
U32 count;
|
||||
ELF_RelocationAdd64 *relocs;
|
||||
} ELFDUMP_Relocs;
|
||||
|
||||
////////////////////////////////
|
||||
// ELF DUMP Arguments Functions
|
||||
|
||||
function ELFDUMP_Arguments* elfdump_args(Arena *arena, String8List *args);
|
||||
|
||||
////////////////////////////////
|
||||
// Entry Point
|
||||
|
||||
int main(int argc, char **argv);
|
||||
|
||||
#endif //MR4TH_ELF_DUMP_H
|
||||
|
|
@ -0,0 +1,705 @@
|
|||
#ifndef MR4TH_ELF_H
|
||||
#define MR4TH_ELF_H
|
||||
|
||||
/*
|
||||
** ELF total layout summary:
|
||||
**
|
||||
** TODO
|
||||
*/
|
||||
|
||||
////////////////////////////////
|
||||
// Types: ELF
|
||||
|
||||
// identification
|
||||
|
||||
#define ELF_NUM_IDENT 16
|
||||
|
||||
#define ELF_IdentificationIdx_XList(X)\
|
||||
X(MAG0, 0)\
|
||||
X(MAG1, 1)\
|
||||
X(MAG2, 2)\
|
||||
X(MAG3, 3)\
|
||||
X(CLASS, 4)\
|
||||
X(DATA, 5)\
|
||||
X(VERSION, 6)\
|
||||
X(OSABI, 7)\
|
||||
X(ABIVERSION, 8)\
|
||||
X(PAD0, 9)\
|
||||
X(PAD1, 10)\
|
||||
X(PAD2, 11)\
|
||||
X(PAD3, 12)\
|
||||
X(PAD4, 13)\
|
||||
X(PAD5, 14)\
|
||||
X(PAD6, 15)
|
||||
|
||||
typedef enum ELF_IdentificationIdx{
|
||||
#define X(N,C) ELF_IdentificationIdx_##N = C,
|
||||
ELF_IdentificationIdx_XList(X)
|
||||
#undef X
|
||||
} ELF_IdentificationIdx;
|
||||
|
||||
#define ELF_Magic_Byte0 0x7F
|
||||
#define ELF_Magic_Byte1 'E'
|
||||
#define ELF_Magic_Byte2 'L'
|
||||
#define ELF_Magic_Byte3 'F'
|
||||
|
||||
// elf class
|
||||
|
||||
#define ELF_Class_XList(X)\
|
||||
X(NONE, 0)\
|
||||
X(32, 1)\
|
||||
X(64, 2)
|
||||
|
||||
typedef enum ELF_Class{
|
||||
#define X(N,C) ELF_Class_##N = C,
|
||||
ELF_Class_XList(X)
|
||||
#undef X
|
||||
} ELF_Class;
|
||||
|
||||
// elf encoding
|
||||
|
||||
#define ELF_Encoding_XList(X)\
|
||||
X(NONE, 0)\
|
||||
X(2LSB, 1)\
|
||||
X(2MSB, 2)
|
||||
|
||||
typedef enum ELF_Encoding{
|
||||
#define X(N,C) ELF_Encoding_##N = C,
|
||||
ELF_Encoding_XList(X)
|
||||
#undef X
|
||||
} ELF_Encoding;
|
||||
|
||||
// elf os/abi extension
|
||||
|
||||
#define ELF_OsAbiExtension_XList(X)\
|
||||
X(NONE, 0)\
|
||||
X(HPUX, 1)\
|
||||
X(NETBSD, 2)\
|
||||
X(GNU, 3)\
|
||||
X(SOLARIS, 6)\
|
||||
X(AIX, 7)\
|
||||
X(IRIX, 8)\
|
||||
X(FREEBSD, 9)\
|
||||
X(TRU64, 10)\
|
||||
X(MODESTO, 11)\
|
||||
X(OPENBSD, 12)\
|
||||
X(OPENVMS, 13)\
|
||||
X(NSK, 14)\
|
||||
X(AROS, 15)\
|
||||
X(FENIXOS, 16)\
|
||||
X(CLOUDABI, 17)\
|
||||
X(OPENVOS, 18)
|
||||
|
||||
typedef enum ELF_OsAbiExtension{
|
||||
#define X(N,C) ELF_OsAbiExtension_##N = C,
|
||||
ELF_OsAbiExtension_XList(X)
|
||||
#undef X
|
||||
} ELF_OsAbiExtension;
|
||||
|
||||
// file type
|
||||
|
||||
#define ELF_FileType_XList(X)\
|
||||
X(NONE, 0)\
|
||||
X(REL, 1)\
|
||||
X(EXEC, 2)\
|
||||
X(DYN, 3)\
|
||||
X(CORE, 4)\
|
||||
X(LOOS, 0xfe00)\
|
||||
X(HIOS, 0xfeff)\
|
||||
X(LOPROC, 0xff00)\
|
||||
X(HIPROC, 0xffff)
|
||||
|
||||
typedef U16 ELF_FileType;
|
||||
enum{
|
||||
#define X(N,C) ELF_FileType_##N = C,
|
||||
ELF_FileType_XList(X)
|
||||
#undef X
|
||||
};
|
||||
|
||||
// machine type
|
||||
|
||||
#define ELF_MachineType_XList(X)\
|
||||
X(NONE, 0)\
|
||||
X(M32, 1)\
|
||||
X(SPARC, 2)\
|
||||
X(386, 3)\
|
||||
X(68K, 4)\
|
||||
X(88K, 5)\
|
||||
X(IAMCU, 6)\
|
||||
X(860, 7)\
|
||||
X(MIPS, 8)\
|
||||
X(S370, 9)\
|
||||
X(MIPS_RS3_LE, 10)\
|
||||
X(PARISC, 15)\
|
||||
X(VPP500, 17)\
|
||||
X(SPARC32PLUS, 18)\
|
||||
X(960, 19)\
|
||||
X(PPC, 20)\
|
||||
X(PPC64, 21)\
|
||||
X(S390, 22)\
|
||||
X(SPU, 23)\
|
||||
X(V800, 36)\
|
||||
X(FR20, 37)\
|
||||
X(RH32, 38)\
|
||||
X(RCE, 39)\
|
||||
X(ARM, 40)\
|
||||
X(ALPHA, 41)\
|
||||
X(SH, 42)\
|
||||
X(SPARCV9, 43)\
|
||||
X(TRICORE, 44)\
|
||||
X(ARC, 45)\
|
||||
X(H8_300, 300)\
|
||||
X(H8S, 48)\
|
||||
X(H8_500, 49)\
|
||||
X(IA_64, 50)\
|
||||
X(MIPS_X, 51)\
|
||||
X(COLDFIRE, 52)\
|
||||
X(68HC12, 53)\
|
||||
X(MMA, 54)\
|
||||
X(PCP, 55)\
|
||||
X(NCPU, 56)\
|
||||
X(NDR1, 57)\
|
||||
X(STARCORE, 58)\
|
||||
X(ME16, 59)\
|
||||
X(ST100, 60)\
|
||||
X(TINYJ, 61)\
|
||||
X(X86_64, 62)\
|
||||
X(PDSP, 63)\
|
||||
X(PDP10, 64)\
|
||||
X(PDP11, 65)\
|
||||
X(FX66, 66)\
|
||||
X(ST9PLUS, 67)\
|
||||
X(ST7, 68)\
|
||||
X(68HC16, 69)\
|
||||
X(68HC11, 70)\
|
||||
X(68HC08, 71)\
|
||||
X(68HC05, 72)\
|
||||
X(SVX, 73)\
|
||||
X(ST19, 74)\
|
||||
X(VAX, 75)\
|
||||
X(CRIS, 76)\
|
||||
X(JAVELIN, 77)\
|
||||
X(FIREPATH, 78)\
|
||||
X(ZSP, 79)\
|
||||
X(MMIX, 80)\
|
||||
X(HUANY, 81)\
|
||||
X(PRISM, 82)\
|
||||
X(AVR, 83)\
|
||||
X(FR30, 84)\
|
||||
X(D10V, 85)\
|
||||
X(D30V, 86)\
|
||||
X(V850, 87)\
|
||||
X(M32R, 88)\
|
||||
X(MN10300, 89)\
|
||||
X(MN10200, 90)\
|
||||
X(PJ, 91)\
|
||||
X(OPENRISC, 92)\
|
||||
X(ARC_COMPACT, 93)\
|
||||
X(XTENSA, 94)\
|
||||
X(VIDEOCORE, 95)\
|
||||
X(TMM_GPP, 96)\
|
||||
X(NS32K, 97)\
|
||||
X(TPC, 98)\
|
||||
X(SNP1K, 99)\
|
||||
X(ST200, 100)\
|
||||
X(IP2K, 101)\
|
||||
X(MAX, 102)\
|
||||
X(CR, 103)\
|
||||
X(F2MC16, 104)\
|
||||
X(MSP430, 105)\
|
||||
X(BLACKFIN, 106)\
|
||||
X(SE_C33, 107)\
|
||||
X(SEP, 108)\
|
||||
X(ARCA, 109)\
|
||||
X(UNICORE, 110)\
|
||||
X(EXCESS, 111)\
|
||||
X(DXP, 112)\
|
||||
X(ALTERA_NIOS2, 113)\
|
||||
X(CRX, 114)\
|
||||
X(XGATE, 115)\
|
||||
X(C166, 116)\
|
||||
X(M16C, 117)\
|
||||
X(DSPIC30F, 118)\
|
||||
X(CE, 119)\
|
||||
X(M32C, 120)\
|
||||
X(TSK3000, 131)\
|
||||
X(RS08, 132)\
|
||||
X(SHARC, 133)\
|
||||
X(ECOG2, 134)\
|
||||
X(SCORE7, 135)\
|
||||
X(DSP24, 136)\
|
||||
X(VIDEOCORE3, 137)\
|
||||
X(LATTICEMICO32, 138)\
|
||||
X(SE_C17, 139)\
|
||||
X(TI_C6000, 140)\
|
||||
X(TI_C2000, 141)\
|
||||
X(TI_C5500, 142)\
|
||||
X(TI_ARP32, 143)\
|
||||
X(TI_PRU, 144)\
|
||||
X(MMDSP_PLUS, 160)\
|
||||
X(CYPRESS_M8C, 161)\
|
||||
X(R32C, 162)\
|
||||
X(TRIMEDIA, 163)\
|
||||
X(QDSP6, 164)\
|
||||
X(8051, 165)\
|
||||
X(STXP7X, 166)\
|
||||
X(NDS32, 167)\
|
||||
X(ECOG1, 168)\
|
||||
X(MAXQ30, 169)\
|
||||
X(XIMO16, 170)\
|
||||
X(MANIK, 171)\
|
||||
X(CRAYNV2, 172)\
|
||||
X(RX, 173)\
|
||||
X(METAG, 174)\
|
||||
X(MCST_ELBRUS, 175)\
|
||||
X(ECOG16, 176)\
|
||||
X(CR16, 177)\
|
||||
X(ETPU, 178)\
|
||||
X(SLE9X, 179)\
|
||||
X(L10M, 180)\
|
||||
X(K10M, 181)\
|
||||
X(AARCH64, 183)\
|
||||
X(AVR32, 185)\
|
||||
X(STM8, 186)\
|
||||
X(TILE64, 187)\
|
||||
X(TILEPRO, 188)\
|
||||
X(MICROBLAZE, 189)\
|
||||
X(CUDA, 190)\
|
||||
X(TILEGX, 191)\
|
||||
X(CLOUDSHIELD, 192)\
|
||||
X(COREA_1ST, 193)\
|
||||
X(COREA_2ND, 194)\
|
||||
X(ARC_COMPACT2, 195)\
|
||||
X(OPEN8, 196)\
|
||||
X(RL78, 197)\
|
||||
X(VIDEOCORE5, 198)\
|
||||
X(78KOR, 199)\
|
||||
X(56800EX, 200)\
|
||||
X(BA1, 201)\
|
||||
X(BA2, 202)\
|
||||
X(XCORE, 203)\
|
||||
X(MCHP_PIC, 204)\
|
||||
X(INTEL205, 205)\
|
||||
X(INTEL206, 206)\
|
||||
X(INTEL207, 207)\
|
||||
X(INTEL208, 208)\
|
||||
X(INTEL209, 209)\
|
||||
X(KM32, 210)\
|
||||
X(KMX32, 211)\
|
||||
X(KMX16, 212)\
|
||||
X(KMX8, 213)\
|
||||
X(KVARC, 214)\
|
||||
X(CDP, 215)\
|
||||
X(COGE, 216)\
|
||||
X(COOL, 217)\
|
||||
X(NORC, 218)\
|
||||
X(CSR_KALIMBA, 219)\
|
||||
X(Z80, 220)\
|
||||
X(VISIUM, 221)\
|
||||
X(FT32, 222)\
|
||||
X(MOXIE, 223)\
|
||||
X(AMDGPU, 224)\
|
||||
X(RISCV, 243)
|
||||
|
||||
typedef U16 ELF_MachineType;
|
||||
|
||||
// elf header
|
||||
|
||||
typedef struct ELF_Header32{
|
||||
U8 ident[ELF_NUM_IDENT];
|
||||
ELF_FileType type;
|
||||
ELF_MachineType machine;
|
||||
U32 version;
|
||||
U32 entry;
|
||||
U32 segment_table_foff;
|
||||
U32 section_table_foff;
|
||||
U32 flags;
|
||||
U16 header_size;
|
||||
U16 segment_size;
|
||||
U16 segment_count;
|
||||
U16 section_size;
|
||||
U16 section_count;
|
||||
U16 string_section_index;
|
||||
} ELF_Header32;
|
||||
|
||||
typedef struct ELF_Header64{
|
||||
U8 ident[ELF_NUM_IDENT];
|
||||
ELF_FileType type;
|
||||
ELF_MachineType machine;
|
||||
U32 version;
|
||||
U64 entry;
|
||||
U64 segment_table_foff;
|
||||
U64 section_table_foff;
|
||||
U32 flags;
|
||||
U16 header_size;
|
||||
U16 segment_size;
|
||||
U16 segment_count;
|
||||
U16 section_size;
|
||||
U16 section_count;
|
||||
U16 string_section_index;
|
||||
} ELF_Header64;
|
||||
|
||||
// elf section type
|
||||
|
||||
#define ELF_SectionType_XList(X)\
|
||||
X(NULL, 0)\
|
||||
X(PROGBITS, 1)\
|
||||
X(SYMTAB, 2)\
|
||||
X(STRTAB, 3)\
|
||||
X(RELA, 4)\
|
||||
X(HASH, 5)\
|
||||
X(DYNAMIC, 6)\
|
||||
X(NOTE, 7)\
|
||||
X(NOBITS, 8)\
|
||||
X(REL, 9)\
|
||||
X(SHLIB, 10)\
|
||||
X(DYNSYM, 11)\
|
||||
X(INIT_ARRAY, 14)\
|
||||
X(FINI_ARRAY, 15)\
|
||||
X(PREINIT_ARRAY, 16)\
|
||||
X(GROUP, 17)\
|
||||
X(SYMTAB_SHNDX, 18)\
|
||||
X(LOOS, 0x60000000)\
|
||||
X(HIOS, 0x6fffffff)\
|
||||
X(LOPROC, 0x70000000)\
|
||||
X(HIPROC, 0x7fffffff)\
|
||||
X(LOUSER, 0x80000000)\
|
||||
X(HIUSER, 0xffffffff)
|
||||
|
||||
typedef U32 ELF_SectionType;
|
||||
enum{
|
||||
#define X(N,C) ELF_SectionType_##N = C,
|
||||
ELF_SectionType_XList(X)
|
||||
#undef X
|
||||
};
|
||||
|
||||
// elf section flags
|
||||
|
||||
#define ELF_SectionFlags_XList(X)\
|
||||
X(WRITE, 0x1)\
|
||||
X(ALLOC, 0x2)\
|
||||
X(EXECINSTR, 0x4)\
|
||||
X(MERGE, 0x10)\
|
||||
X(STRINGS, 0x20)\
|
||||
X(INFO_LINK, 0x40)\
|
||||
X(LINK_ORDER, 0x80)\
|
||||
X(OS_NONCONFORMING, 0x100)\
|
||||
X(GROUP, 0x200)\
|
||||
X(TLS, 0x400)\
|
||||
X(COMPRESSED, 0x800)\
|
||||
X(MASKOS, 0x0ff00000)\
|
||||
X(MASKPROC, 0xf0000000)
|
||||
|
||||
enum{
|
||||
#define X(N,C) ELF_SectionFlag_##N = C,
|
||||
ELF_SectionFlags_XList(X)
|
||||
#undef X
|
||||
};
|
||||
|
||||
// elf section indexes
|
||||
|
||||
#define ELF_SectionIndex_XList(X)\
|
||||
X(UNDEF, 0)\
|
||||
X(LORESERVE, 0xff00)\
|
||||
X(LOPROC, 0xff00)\
|
||||
X(HIPROC, 0xff1f)\
|
||||
X(LOOS, 0xff20)\
|
||||
X(HIOS, 0xff3f)\
|
||||
X(ABS, 0xfff1)\
|
||||
X(COMMON, 0xfff2)\
|
||||
X(XINDEX, 0xffff)\
|
||||
X(HIRESERVE, 0xffff)
|
||||
|
||||
typedef enum ELF_SectionIndex{
|
||||
#define X(N,C) ELF_SectionIndex_##N = C,
|
||||
ELF_SectionIndex_XList(X)
|
||||
#undef X
|
||||
} ELF_SectionIndex;
|
||||
|
||||
|
||||
// elf section
|
||||
|
||||
typedef struct ELF_Section32{
|
||||
U32 name;
|
||||
ELF_SectionType type;
|
||||
U32 flags;
|
||||
U32 addr;
|
||||
U32 offset;
|
||||
U32 size;
|
||||
U32 link;
|
||||
U32 info;
|
||||
U32 addralign;
|
||||
U32 entsize;
|
||||
} ELF_Section32;
|
||||
|
||||
typedef struct ELF_Section64{
|
||||
U32 name;
|
||||
ELF_SectionType type;
|
||||
U64 flags;
|
||||
U64 addr;
|
||||
U64 offset;
|
||||
U64 size;
|
||||
U32 link;
|
||||
U32 info;
|
||||
U64 addralign;
|
||||
U64 entsize;
|
||||
} ELF_Section64;
|
||||
|
||||
// elf compression type
|
||||
|
||||
#define ELF_CompressionType_XList(X)\
|
||||
X(ZLIB, 1)\
|
||||
X(LOOS, 0x60000000)\
|
||||
X(HIOS, 0x6fffffff)\
|
||||
X(LOPROC, 0x70000000)\
|
||||
X(HIPROC, 0x7fffffff)
|
||||
|
||||
typedef enum ELF_CompressionType{
|
||||
#define X(N,C) ELF_CompressionType_##N = C,
|
||||
ELF_CompressionType_XList(X)
|
||||
#undef X
|
||||
} ELF_CompressionType;
|
||||
|
||||
// elf compression header
|
||||
|
||||
typedef struct ELF_CompressionHeader32{
|
||||
ELF_CompressionType type;
|
||||
U32 size;
|
||||
U32 addralign;
|
||||
} ELF_CompressionHeader32;
|
||||
|
||||
typedef struct ELF_CompressionHeader64{
|
||||
ELF_CompressionType type;
|
||||
U32 reserved;
|
||||
U64 size;
|
||||
U64 addralign;
|
||||
} ELF_CompressionHeader64;
|
||||
|
||||
// elf section group flags
|
||||
|
||||
#define ELF_SectionGroupFlags_XList(X)\
|
||||
X(COMDAT, 0x1)\
|
||||
X(MASKOS, 0x0ff00000)\
|
||||
X(MASKPROC, 0xf0000000)
|
||||
|
||||
typedef U32 ELF_SectionGroupFlags;
|
||||
enum{
|
||||
#define X(N,C) ELF_SectionGroupFlag_##N = C,
|
||||
ELF_SectionGroupFlags_XList(X)
|
||||
#undef X
|
||||
};
|
||||
|
||||
// elf symbol
|
||||
|
||||
typedef struct ELF_Symbol32{
|
||||
U32 name;
|
||||
U32 value;
|
||||
U32 size;
|
||||
U8 info;
|
||||
U8 other;
|
||||
U16 section_index;
|
||||
} ELF_Symbol32;
|
||||
|
||||
typedef struct ELF_Symbol64{
|
||||
U32 name;
|
||||
U8 info;
|
||||
U8 other;
|
||||
U16 section_index;
|
||||
U64 value;
|
||||
U64 size;
|
||||
} ELF_Symbol64;
|
||||
|
||||
#define ELF_Symbol_BindFromInfo(inf) ((inf)>>4)
|
||||
#define ELF_Symbol_TypeFromInfo(inf) ((inf)&0xF)
|
||||
#define ELF_Symbol_InfoFromBindType(bin,typ) (((bin)<<4)|((type)&0xF))
|
||||
|
||||
#define ELF_Symbol_VisFromOther(oth) ((oth)&0x3)
|
||||
#define ELF_Symbol_OtherFromVis(vis) (((vis)&0x3))
|
||||
|
||||
// elf symbol binding
|
||||
|
||||
#define ELF_SymbolBinding_XList(X)\
|
||||
X(LOCAL, 0)\
|
||||
X(GLOBAL, 1)\
|
||||
X(WEAK, 2)\
|
||||
X(LOOS, 10)\
|
||||
X(HIOS, 12)\
|
||||
X(LOPROC, 13)\
|
||||
X(HIPROC, 15)
|
||||
|
||||
typedef enum ELF_SymbolBinding{
|
||||
#define X(N,C) ELF_SymbolBinding_##N = C,
|
||||
ELF_SymbolBinding_XList(X)
|
||||
#undef X
|
||||
} ELF_SymbolBinding;
|
||||
|
||||
// elf symbol types
|
||||
|
||||
#define ELF_SymbolType_XList(X)\
|
||||
X(NOTYPE, 0)\
|
||||
X(OBJECT, 1)\
|
||||
X(FUNC, 2)\
|
||||
X(SECTION, 3)\
|
||||
X(FILE, 4)\
|
||||
X(COMMON, 5)\
|
||||
X(TLS, 6)\
|
||||
X(LOOS, 10)\
|
||||
X(HIOS, 12)\
|
||||
X(LOPROC, 13)\
|
||||
X(HIPROC, 15)
|
||||
|
||||
typedef enum ELF_SymbolType{
|
||||
#define X(N,C) ELF_SymbolType_##N = C,
|
||||
ELF_SymbolType_XList(X)
|
||||
#undef X
|
||||
} ELF_SymbolType;
|
||||
|
||||
// elf symbol visibility
|
||||
|
||||
#define ELF_SymbolVis_XList(X)\
|
||||
X(DEFAULT, 0)\
|
||||
X(INTERNAL, 1)\
|
||||
X(HIDDEN, 2)\
|
||||
X(PROTECTED, 3)
|
||||
|
||||
typedef enum ELF_SymbolVis{
|
||||
#define X(N,C) ELF_SymbolVis_##N = C,
|
||||
ELF_SymbolVis_XList(X)
|
||||
#undef X
|
||||
} ELF_SymbolVis;
|
||||
|
||||
// elf relocations
|
||||
|
||||
typedef struct ELF_Relocation32{
|
||||
U32 offset;
|
||||
U32 info;
|
||||
} ELF_Relocation32;
|
||||
|
||||
typedef struct ELF_RelocationAdd32{
|
||||
U32 offset;
|
||||
U32 info;
|
||||
S32 addend;
|
||||
} ELF_RelocationAdd32;
|
||||
|
||||
typedef struct ELF_Relocation64{
|
||||
U64 offset;
|
||||
U64 info;
|
||||
} ELF_Relocation64;
|
||||
|
||||
typedef struct ELF_RelocationAdd64{
|
||||
U64 offset;
|
||||
U64 info;
|
||||
S64 addend;
|
||||
} ELF_RelocationAdd64;
|
||||
|
||||
// elf segment type
|
||||
|
||||
#define ELF_SegmentType_XList(X)\
|
||||
X(NULL, 0)\
|
||||
X(LOAD, 1)\
|
||||
X(DYNAMIC, 2)\
|
||||
X(INTERP, 3)\
|
||||
X(NOTE, 4)\
|
||||
X(SHLIB, 5)\
|
||||
X(PHDR, 6)\
|
||||
X(TLS, 7)\
|
||||
X(LOOS, 0x60000000)\
|
||||
X(HIOS, 0x6fffffff)\
|
||||
X(LOPROC, 0x70000000)\
|
||||
X(HIPROC, 0x7fffffff)
|
||||
|
||||
typedef U32 ELF_SegmentType;
|
||||
enum{
|
||||
#define X(N,C) ELF_SegmentType_##N = C,
|
||||
ELF_SegmentType_XList(X)
|
||||
#undef X
|
||||
};
|
||||
|
||||
// elf segment flags
|
||||
|
||||
#define ELF_SegmentFlags_XList(X)\
|
||||
X(X, 0x1)\
|
||||
X(W, 0x2)\
|
||||
X(R, 0x4)\
|
||||
X(MASKOS, 0x0ff00000)\
|
||||
X(MASKPROC, 0xf0000000)\
|
||||
|
||||
typedef U32 ELF_SegmentFlags;
|
||||
enum{
|
||||
#define X(N,C) ELF_SegmentFlag_##N = C,
|
||||
ELF_SegmentFlags_XList(X)
|
||||
#undef X
|
||||
};
|
||||
|
||||
// elf segment
|
||||
|
||||
typedef struct ELF_Segment32{
|
||||
ELF_SegmentType type;
|
||||
U32 offset;
|
||||
U32 vaddr;
|
||||
U32 paddr;
|
||||
U32 file_size;
|
||||
U32 memory_size;
|
||||
ELF_SegmentFlags flags;
|
||||
U32 align;
|
||||
} ELF_Segment32;
|
||||
|
||||
typedef struct ELF_Segment64{
|
||||
ELF_SegmentType type;
|
||||
ELF_SegmentFlags flags;
|
||||
U64 offset;
|
||||
U64 vaddr;
|
||||
U64 paddr;
|
||||
U64 file_size;
|
||||
U64 memory_size;
|
||||
U64 align;
|
||||
} ELF_Segment64;
|
||||
|
||||
////////////////////////////////
|
||||
// Functions: ELF
|
||||
|
||||
// normalizing
|
||||
|
||||
MR4TH_SYM_COMPTIME U16 elf_u16_decode(void *ptr, B32 flip);
|
||||
MR4TH_SYM_COMPTIME U32 elf_u32_decode(void *ptr, B32 flip);
|
||||
MR4TH_SYM_COMPTIME U64 elf_u64_decode(void *ptr, B32 flip);
|
||||
|
||||
MR4TH_SYM_COMPTIME void elf_header64_from_header32(ELF_Header64 *dst, ELF_Header32 *src, ELF_Encoding src_encoding);
|
||||
MR4TH_SYM_COMPTIME void elf_header64_from_header64(ELF_Header64 *dst, ELF_Header64 *src, ELF_Encoding src_encoding);
|
||||
|
||||
MR4TH_SYM_COMPTIME void elf_section64_from_section32(ELF_Section64 *dst, ELF_Section32 *src, ELF_Encoding src_encoding);
|
||||
MR4TH_SYM_COMPTIME void elf_section64_from_section64(ELF_Section64 *dst, ELF_Section64 *src, ELF_Encoding src_encoding);
|
||||
|
||||
MR4TH_SYM_COMPTIME void elf_segment64_from_segment32(ELF_Segment64 *dst, ELF_Segment32 *src, ELF_Encoding src_encoding);
|
||||
MR4TH_SYM_COMPTIME void elf_segment64_from_segment64(ELF_Segment64 *dst, ELF_Segment64 *src, ELF_Encoding src_encoding);
|
||||
|
||||
MR4TH_SYM_COMPTIME void elf_symbol64_from_symbol32(ELF_Symbol64 *dst, ELF_Symbol32 *src, ELF_Encoding src_encoding);
|
||||
MR4TH_SYM_COMPTIME void elf_symbol64_from_symbol64(ELF_Symbol64 *dst, ELF_Symbol64 *src, ELF_Encoding src_encoding);
|
||||
|
||||
MR4TH_SYM_COMPTIME ELF_RelocationAdd64* elf_reloca64_from_reloc32(Arena *arena, ELF_Relocation32 *src, U64 count, ELF_Encoding src_encoding);
|
||||
MR4TH_SYM_COMPTIME ELF_RelocationAdd64* elf_reloca64_from_reloc64(Arena *arena, ELF_Relocation64 *src, U64 count, ELF_Encoding src_encoding);
|
||||
MR4TH_SYM_COMPTIME ELF_RelocationAdd64* elf_reloca64_from_reloca32(Arena *arena, ELF_RelocationAdd32 *src, U64 count, ELF_Encoding src_encoding);
|
||||
MR4TH_SYM_COMPTIME ELF_RelocationAdd64* elf_reloca64_from_reloca64(Arena *arena, ELF_RelocationAdd64 *src, U64 count, ELF_Encoding src_encoding);
|
||||
|
||||
// strings
|
||||
|
||||
MR4TH_SYM_COMPTIME String8 elf_str8_from_identification_idx(ELF_IdentificationIdx idx);
|
||||
MR4TH_SYM_COMPTIME String8 elf_str8_from_class(ELF_Class elf_class);
|
||||
MR4TH_SYM_COMPTIME String8 elf_str8_from_encoding(ELF_Encoding elf_encoding);
|
||||
MR4TH_SYM_COMPTIME String8 elf_str8_from_osabi(ELF_OsAbiExtension elf_osabi);
|
||||
MR4TH_SYM_COMPTIME String8 elf_str8_from_file_type(ELF_FileType file_type);
|
||||
MR4TH_SYM_COMPTIME String8 elf_str8_from_machine_type(ELF_FileType machine_type);
|
||||
|
||||
MR4TH_SYM_COMPTIME String8 elf_str8_from_section_type(ELF_SectionType section_type);
|
||||
MR4TH_SYM_COMPTIME void elf_str8list_from_section_flags(Arena *arena, String8List *out, U32 flags);
|
||||
MR4TH_SYM_COMPTIME String8 elf_str8_from_section_flags(Arena *arena, U32 flags);
|
||||
|
||||
MR4TH_SYM_COMPTIME String8 elf_str8_from_segment_type(ELF_SegmentType segment_type);
|
||||
MR4TH_SYM_COMPTIME void elf_str8list_from_segment_flags(Arena *arena, String8List *out, ELF_SegmentFlags flags);
|
||||
MR4TH_SYM_COMPTIME String8 elf_str8_from_segment_flags(Arena *arena, ELF_SegmentFlags flags);
|
||||
|
||||
MR4TH_SYM_COMPTIME String8 elf_str8_from_symbol_binding(ELF_SymbolBinding bind);
|
||||
MR4TH_SYM_COMPTIME String8 elf_str8_from_symbol_type(ELF_SymbolType type);
|
||||
MR4TH_SYM_COMPTIME String8 elf_str8_from_symbol_vis(ELF_SymbolVis vis);
|
||||
|
||||
#endif //MR4TH_ELF_H
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef MR4TH_BINARY_H
|
||||
#define MR4TH_BINARY_H
|
||||
|
||||
/* TODO:
|
||||
** BINARY FILE PROJECT
|
||||
**
|
||||
** Research Questions:
|
||||
** [ ] What the heck is that blob of data between the
|
||||
** DOS header and the PE signature/COFF header?
|
||||
** And why does it change so much from binary to binary?
|
||||
** [ ] Unwind Info: The docs say there is a ULONG after the unwind codes???
|
||||
**
|
||||
** TASKS:
|
||||
**
|
||||
** [x] Useful PE/COFF Table Tool
|
||||
** [ ] PE/COFF Linker
|
||||
** [ ] PE/COFF ObjFromRaw
|
||||
** [ ] PE/COFF editing to hard wire magic IDs without a data section
|
||||
** [ ] PE/COFF editing to merge separate data sections to
|
||||
** consolidate magic gathered arrays into plain old .data
|
||||
**
|
||||
** [ ] Renaming pass over mr4th_elf.dump (similar to pe.dump -> pe.parsex)
|
||||
** [ ] ELF Generator
|
||||
** [ ] Useful ELF ASCII Visualizer
|
||||
** [ ] ELF Linker
|
||||
** [ ] Debug Information (CODEVIEW,DWARF)
|
||||
**
|
||||
*/
|
||||
|
||||
#endif //MR4TH_BINARY_H
|
||||
|
|
@ -0,0 +1,277 @@
|
|||
////////////////////////////////
|
||||
// Functions: COFF / PE
|
||||
|
||||
// properties
|
||||
|
||||
MR4TH_SYM_COMPTIME U32
|
||||
pe_unwind_num_code_slot_from_opcode_opinfo(PE_UnwindOpCode opcode, U8 opinfo){
|
||||
U32 num = 1;
|
||||
|
||||
switch (opcode){
|
||||
case PE_UnwindOpCode_PUSH_NONVOL:
|
||||
case PE_UnwindOpCode_ALLOC_SMALL:
|
||||
case PE_UnwindOpCode_SET_FPREG:
|
||||
case PE_UnwindOpCode_PUSH_MACHFRAME:
|
||||
case PE_UnwindOpCode_EPILOG:
|
||||
case PE_UnwindOpCode_SPARE:
|
||||
{
|
||||
num = 1;
|
||||
}break;
|
||||
|
||||
case PE_UnwindOpCode_ALLOC_LARGE:
|
||||
{
|
||||
if (opinfo == 0){
|
||||
num = 2;
|
||||
}
|
||||
else{
|
||||
num = 3;
|
||||
}
|
||||
}break;
|
||||
|
||||
case PE_UnwindOpCode_SAVE_NONVOL:
|
||||
case PE_UnwindOpCode_SAVE_XMM128:
|
||||
{
|
||||
num = 2;
|
||||
}break;
|
||||
|
||||
case PE_UnwindOpCode_SAVE_NONVOL_FAR:
|
||||
case PE_UnwindOpCode_SAVE_XMM128_FAR:
|
||||
{
|
||||
num = 3;
|
||||
}break;
|
||||
}
|
||||
|
||||
return(num);
|
||||
}
|
||||
|
||||
// checks
|
||||
|
||||
MR4TH_SYM_COMPTIME B32
|
||||
pe_machine_type_is_valid(PE_MachineType machine_type){
|
||||
B32 result = 0;
|
||||
switch (machine_type){
|
||||
#define X(N,C) case C:
|
||||
PE_MachineType_XList(X)
|
||||
#undef X
|
||||
result = 1; break;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
// strings
|
||||
|
||||
MR4TH_SYM_COMPTIME String8
|
||||
pe_str8_from_machine_type(PE_MachineType machine_type){
|
||||
String8 result = str8_lit("ERROR");
|
||||
switch (machine_type){
|
||||
#define X(N,C) case C: result = str8_lit(#N); break;
|
||||
PE_MachineType_XList(X)
|
||||
#undef X
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME void
|
||||
pe_str8list_from_flags(Arena *arena, String8List *out, PE_Flags flags){
|
||||
U32 f = 1;
|
||||
for (U32 i = 0; i < 8*sizeof(flags); i += 1){
|
||||
if ((flags & f) != 0){
|
||||
switch (f){
|
||||
#define X(N,C) case C: str8_list_push(arena, out, str8_lit(#N)); break;
|
||||
PE_Flags_XList(X)
|
||||
#undef X
|
||||
}
|
||||
}
|
||||
f <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME String8
|
||||
pe_str8_from_flags(Arena *arena, PE_Flags flags){
|
||||
ArenaTemp scratch = arena_get_scratch(&arena, 1);
|
||||
String8List list = {0};
|
||||
pe_str8list_from_flags(scratch.arena, &list, flags);
|
||||
String8 result = str8_join_flags(arena, &list);
|
||||
arena_release_scratch(&scratch);
|
||||
return(result);
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME String8
|
||||
pe_str8_from_optional_header_magic(PE_OptionalHeaderMagic magic){
|
||||
String8 result = str8_lit("ERROR");
|
||||
switch (magic){
|
||||
#define X(N,C) case C: result = str8_lit(#N); break;
|
||||
PE_OptionalHeaderMagic_XList(X)
|
||||
#undef X
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME String8
|
||||
pe_str8_from_windows_subsystem(PE_WindowsSubsystem subsystem){
|
||||
String8 result = str8_lit("ERROR");
|
||||
switch (subsystem){
|
||||
#define X(N,C) case C: result = str8_lit(#N); break;
|
||||
PE_WindowsSubsystem_XList(X)
|
||||
#undef X
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME void
|
||||
pe_str8list_from_dll_flags(Arena *arena, String8List *out, PE_DLLFlags dll_flags){
|
||||
U32 f = 1;
|
||||
for (U32 i = 0; i < 8*sizeof(dll_flags); i += 1){
|
||||
if ((dll_flags & f) != 0){
|
||||
switch (f){
|
||||
#define X(N,C) case C: str8_list_push(arena, out, str8_lit(#N)); break;
|
||||
PE_DLLFlags_XList(X)
|
||||
#undef X
|
||||
}
|
||||
}
|
||||
f <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME String8
|
||||
pe_str8_from_dll_flags(Arena *arena, PE_DLLFlags dll_flags){
|
||||
ArenaTemp scratch = arena_get_scratch(&arena, 1);
|
||||
String8List list = {0};
|
||||
pe_str8list_from_dll_flags(scratch.arena, &list, dll_flags);
|
||||
String8 result = str8_join_flags(arena, &list);
|
||||
arena_release_scratch(&scratch);
|
||||
return(result);
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME String8
|
||||
pe_str8_from_data_directory_idx(PE_DataDirectoryIdx idx){
|
||||
String8 result = {0};
|
||||
switch (idx){
|
||||
#define X(N,D,C) case C: result = str8_lit(#N); break;
|
||||
PE_DataDirectoryIdx_XList(X)
|
||||
#undef X
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME String8
|
||||
pe_str8_display_string_from_data_directory_idx(PE_DataDirectoryIdx idx){
|
||||
String8 result = {0};
|
||||
switch (idx){
|
||||
#define X(N,D,C) case C: result = str8_lit(D); break;
|
||||
PE_DataDirectoryIdx_XList(X)
|
||||
#undef X
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME String8
|
||||
pe_str8_from_sec_alignment(U32 alignment){
|
||||
String8 result = {0};
|
||||
switch (alignment){
|
||||
#define X(Z,C) case C: result = str8_lit("ALIGN_" #Z "BYTES"); break;
|
||||
PE_SectionAlign_XList(X)
|
||||
#undef X
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME void
|
||||
pe_str8list_from_sec_flags(Arena *arena, String8List *out, PE_SectionFlags sec_flags){
|
||||
// align
|
||||
U32 section_align = PE_SectionAlignFromSectionFlags(sec_flags);
|
||||
String8 align_str = pe_str8_from_sec_alignment(section_align);
|
||||
if (align_str.size > 0){
|
||||
str8_list_push(arena, out, align_str);
|
||||
}
|
||||
|
||||
// other flags
|
||||
U32 f = 1;
|
||||
for (U32 i = 0; i < 8*sizeof(sec_flags); i += 1){
|
||||
if ((sec_flags & f) != 0){
|
||||
switch (f){
|
||||
#define X(N,C) case C: str8_list_push(arena, out, str8_lit(#N)); break;
|
||||
PE_SectionFlags_XList(X)
|
||||
#undef X
|
||||
}
|
||||
}
|
||||
f <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME String8
|
||||
pe_str8_from_sec_flags(Arena *arena, PE_SectionFlags sec_flags){
|
||||
ArenaTemp scratch = arena_get_scratch(&arena, 1);
|
||||
String8List list = {0};
|
||||
pe_str8list_from_sec_flags(scratch.arena, &list, sec_flags);
|
||||
String8 result = str8_join_flags(arena, &list);
|
||||
arena_release_scratch(&scratch);
|
||||
return(result);
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME String8
|
||||
pe_str8_from_coff_relocation_type(PE_CoffRelocationType type){
|
||||
String8 result = str8_lit("ERROR");
|
||||
switch (type){
|
||||
#define X(N,C) case C: result = str8_lit(#N); break;
|
||||
PE_CoffRelocationType_XList(X)
|
||||
#undef X
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME String8
|
||||
pe_str8_from_coff_symbol_type(Arena *arena, PE_CoffSymbolType type){
|
||||
String8 lo = str8_lit("ERROR");
|
||||
switch (type & 0xF){
|
||||
#define X(N,C) case C: lo = str8_lit(#N); break;
|
||||
PE_CoffSymbolTypeLo_XList(X)
|
||||
#undef X
|
||||
}
|
||||
|
||||
String8 result = lo;
|
||||
switch ((type >> 4) & 0xF){
|
||||
case PE_CoffSymbolTypeHi_NULL: break;
|
||||
case PE_CoffSymbolTypeHi_POINTER:
|
||||
result = str8_pushf(arena, "POINTER %S", lo); break;
|
||||
case PE_CoffSymbolTypeHi_FUNCTION:
|
||||
result = str8_pushf(arena, "FUNCTION %S", lo); break;
|
||||
case PE_CoffSymbolTypeHi_ARRAY:
|
||||
result = str8_pushf(arena, "ARRAY %S", lo); break;
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME String8
|
||||
pe_str8_from_coff_symbol_storage_class(PE_CoffSymbolStorageClass storage_class){
|
||||
String8 result = str8_lit("ERROR");
|
||||
switch (storage_class){
|
||||
#define X(N,C) case C: result = str8_lit(#N); break;
|
||||
PE_CoffSymbolStorageClass_XList(X)
|
||||
#undef X
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME String8
|
||||
pe_str8_from_base_relocation_type(PE_BaseRelocationType type){
|
||||
String8 result = str8_lit("ERROR");
|
||||
switch (type){
|
||||
#define X(N,C) case C: result = str8_lit(#N); break;
|
||||
PE_BaseRelocationType_XList(X)
|
||||
#undef X
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
MR4TH_SYM_COMPTIME String8
|
||||
pe_str8_from_debug_type(PE_DebugType debug_type){
|
||||
String8 result = str8_lit("ERROR");
|
||||
switch (debug_type){
|
||||
#define X(N,C) case C: result = str8_lit(#N); break;
|
||||
PE_DebugType_XList(X)
|
||||
#undef X
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,463 @@
|
|||
#ifndef MR4TH_PE_GEN_H
|
||||
#define MR4TH_PE_GEN_H
|
||||
|
||||
////////////////////////////////
|
||||
// PE Generator Types
|
||||
|
||||
// data block system
|
||||
|
||||
typedef struct PEGEN_Block{
|
||||
struct PEGEN_Block *next_bucket;
|
||||
struct PEGEN_Block *next_sibling;
|
||||
struct PEGEN_Block *first_child;
|
||||
struct PEGEN_Block *last_child;
|
||||
struct PEGEN_Block *parent;
|
||||
U32 child_count;
|
||||
B8 attached;
|
||||
U8 padding_fillbyte;
|
||||
U32 base_alignment;
|
||||
U8 *data;
|
||||
U32 total_size;
|
||||
U32 off_within_parent;
|
||||
} PEGEN_Block;
|
||||
|
||||
typedef struct PEGEN_Ctx{
|
||||
Arena *arena;
|
||||
|
||||
PEGEN_Block *first_block;
|
||||
PEGEN_Block *last_block;
|
||||
U64 block_count;
|
||||
} PEGEN_Ctx;
|
||||
|
||||
typedef struct PEGEN_Label{
|
||||
PEGEN_Block *block;
|
||||
U32 off;
|
||||
} PEGEN_Label;
|
||||
|
||||
// sections
|
||||
|
||||
typedef struct PEGEN_Section{
|
||||
struct PEGEN_Section *next;
|
||||
PEGEN_Block *block;
|
||||
U8 *name;
|
||||
U32 name_size;
|
||||
U16 secnum;
|
||||
PE_SectionFlags flags;
|
||||
U32 vsize;
|
||||
struct PEGEN_CoffRelocList *coff_relocs;
|
||||
} PEGEN_Section;
|
||||
|
||||
typedef struct PEGEN_SectionList{
|
||||
PEGEN_Section *first;
|
||||
PEGEN_Section *last;
|
||||
U64 count;
|
||||
} PEGEN_SectionList;
|
||||
|
||||
// patches for pe/coff files
|
||||
|
||||
typedef enum PEGEN_PatchKind{
|
||||
PEGEN_PatchKind_FileAbsolute,
|
||||
PEGEN_PatchKind_FileRelative,
|
||||
PEGEN_PatchKind_VirtAbsolute,
|
||||
PEGEN_PatchKind_VirtRelative,
|
||||
PEGEN_PatchKind_VirtAddress,
|
||||
PEGEN_PatchKind_SectionNumber,
|
||||
PEGEN_PatchKind_SectionOffset,
|
||||
} PEGEN_PatchKind;
|
||||
|
||||
typedef struct PEGEN_Patch{
|
||||
struct PEGEN_Patch *next;
|
||||
|
||||
// positions
|
||||
PEGEN_Label patchpos;
|
||||
PEGEN_Label targetpos;
|
||||
|
||||
// patch bits
|
||||
U8 patch_bitoff;
|
||||
U8 patch_numbits;
|
||||
|
||||
// value calculation
|
||||
PEGEN_PatchKind kind;
|
||||
S8 bias;
|
||||
U8 shift;
|
||||
|
||||
// val = ( (flags.SecIdx?IdxOf(SecOf(target)):VoffOf(target))
|
||||
// + (flags.Vaddr?ImageBaseVaddr:0)
|
||||
// - (flags.RelocRel?AddrOf(reloc):0)
|
||||
// - (flags.SecRel?AddrOf(SecOf(target)):0)
|
||||
// + bias) >> shift
|
||||
|
||||
} PEGEN_Patch;
|
||||
|
||||
typedef struct PEGEN_PatchList{
|
||||
PEGEN_Patch *first;
|
||||
PEGEN_Patch *last;
|
||||
U64 count;
|
||||
} PEGEN_PatchList;
|
||||
|
||||
// image config
|
||||
|
||||
typedef struct PEGEN_ImgConfig{
|
||||
U64 base_vaddr;
|
||||
U32 file_align;
|
||||
U32 virt_align;
|
||||
PEGEN_Label entry_point;
|
||||
PEGEN_Block *data_directories[PE_DataDirectoryIdx_COUNT];
|
||||
} PEGEN_ImgConfig;
|
||||
|
||||
// object config
|
||||
|
||||
typedef struct PEGEN_ObjConfig{
|
||||
struct PEGEN_SymbolTableBaked *symbol_table;
|
||||
} PEGEN_ObjConfig;
|
||||
|
||||
// headers & layouts
|
||||
|
||||
typedef struct PEGEN_LayoutSection{
|
||||
PEGEN_Block *block;
|
||||
U8 *name;
|
||||
U32 name_size;
|
||||
U32 voff;
|
||||
U32 foff;
|
||||
U32 vsize;
|
||||
U32 fsize;
|
||||
U16 fsize_padding;
|
||||
PE_SectionFlags flags;
|
||||
U16 reloc_count;
|
||||
PEGEN_Block *reloc_block;
|
||||
} PEGEN_LayoutSection;
|
||||
|
||||
typedef struct PEGEN_Layout{
|
||||
PEGEN_LayoutSection *sections;
|
||||
U32 section_count;
|
||||
U64 image_base_vaddr;
|
||||
} PEGEN_Layout;
|
||||
|
||||
typedef struct PEGEN_HeaderAndLayout{
|
||||
PEGEN_Block *header;
|
||||
PEGEN_Layout *layout;
|
||||
} PEGEN_HeaderAndLayout;
|
||||
|
||||
// symbol table
|
||||
|
||||
typedef struct PEGEN_Symbol{
|
||||
struct PEGEN_Symbol *next;
|
||||
String8 name;
|
||||
PE_CoffSymbolStorageClass storage_class;
|
||||
PE_CoffSymbolType type;
|
||||
PEGEN_Label pos;
|
||||
} PEGEN_Symbol;
|
||||
|
||||
typedef struct PEGEN_SymbolTable{
|
||||
PEGEN_Symbol *first;
|
||||
PEGEN_Symbol *last;
|
||||
U64 count;
|
||||
} PEGEN_SymbolTable;
|
||||
|
||||
typedef struct PEGEN_SymbolTableBaked{
|
||||
PEGEN_Block *block;
|
||||
U64 symbol_count;
|
||||
// TODO(allen): accelerate Ptr -> Idx
|
||||
PEGEN_Symbol **symbols;
|
||||
U32 *symbol_idxs;
|
||||
} PEGEN_SymbolTableBaked;
|
||||
|
||||
// coff relocs
|
||||
|
||||
typedef struct PEGEN_CoffReloc{
|
||||
struct PEGEN_CoffReloc *next;
|
||||
U32 off;
|
||||
PEGEN_Symbol *symbol;
|
||||
PE_CoffRelocationType type;
|
||||
} PEGEN_CoffReloc;
|
||||
|
||||
typedef struct PEGEN_CoffRelocList{
|
||||
PEGEN_CoffReloc *first;
|
||||
PEGEN_CoffReloc *last;
|
||||
U64 count;
|
||||
} PEGEN_CoffRelocList;
|
||||
|
||||
// exports
|
||||
|
||||
typedef struct PEGEN_Export{
|
||||
struct PEGEN_Export *next;
|
||||
|
||||
PEGEN_Label symbol_label;
|
||||
String8 symbol_fwdname;
|
||||
String8List names;
|
||||
} PEGEN_Export;
|
||||
|
||||
typedef struct PEGEN_ExportTable{
|
||||
PEGEN_Export *first;
|
||||
PEGEN_Export *last;
|
||||
U32 count;
|
||||
U32 name_count;
|
||||
|
||||
U32 time_stamp;
|
||||
U16 version_major;
|
||||
U16 version_minor;
|
||||
String8 binary_name;
|
||||
} PEGEN_ExportTable;
|
||||
|
||||
// imports
|
||||
|
||||
typedef struct PEGEN_Import{
|
||||
struct PEGEN_Import *next;
|
||||
String8 name;
|
||||
U16 ordinal;
|
||||
} PEGEN_Import;
|
||||
|
||||
// TODO(allen): renaming - these aren't "tables"
|
||||
typedef struct PEGEN_ImportTable{
|
||||
struct PEGEN_ImportTable *next;
|
||||
|
||||
PEGEN_Import *first;
|
||||
PEGEN_Import *last;
|
||||
U32 count;
|
||||
|
||||
U32 time_stamp;
|
||||
String8 binary_name;
|
||||
} PEGEN_ImportTable;
|
||||
|
||||
typedef struct PEGEN_ImportList{
|
||||
PEGEN_ImportTable *first_table;
|
||||
PEGEN_ImportTable *last_table;
|
||||
U64 table_count;
|
||||
} PEGEN_ImportList;
|
||||
|
||||
typedef struct PEGEN_ImportBlocks{
|
||||
PEGEN_Block *directory_table;
|
||||
PEGEN_Block *iat;
|
||||
PEGEN_Block *import_data;
|
||||
} PEGEN_ImportBlocks;
|
||||
|
||||
// base relocations
|
||||
|
||||
typedef struct PEGEN_BaseRelocationLoose{
|
||||
struct PEGEN_BaseRelocationLoose *next;
|
||||
PE_BaseRelocationType type;
|
||||
PEGEN_Label label;
|
||||
} PEGEN_BaseRelocationLoose;
|
||||
|
||||
typedef struct PEGEN_BaseRelocationList{
|
||||
PEGEN_BaseRelocationLoose *first;
|
||||
PEGEN_BaseRelocationLoose *last;
|
||||
U64 count;
|
||||
} PEGEN_BaseRelocationList;
|
||||
|
||||
typedef struct PEGEN_BaseRelocation{
|
||||
PE_BaseRelocationType type;
|
||||
U32 voff;
|
||||
} PEGEN_BaseRelocation;
|
||||
|
||||
// unwind info
|
||||
|
||||
typedef struct PEGEN_UnwindCode{
|
||||
struct PEGEN_UnwindCode *next;
|
||||
U8 offset;
|
||||
U8 opcode;
|
||||
U8 opinfo;
|
||||
U32 x;
|
||||
} PEGEN_UnwindCode;
|
||||
|
||||
typedef struct PEGEN_UnwindInfo{
|
||||
struct PEGEN_UnwindInfo *next;
|
||||
|
||||
PEGEN_Label start_pos;
|
||||
PEGEN_Label opl_pos;
|
||||
|
||||
PE_UnwindInfoFlags flags;
|
||||
U8 prolog_size;
|
||||
U8 frame_reg;
|
||||
U8 frame_off;
|
||||
|
||||
PEGEN_UnwindCode *first_code;
|
||||
PEGEN_UnwindCode *last_code;
|
||||
U8 code_count;
|
||||
U8 code_slot_count;
|
||||
} PEGEN_UnwindInfo;
|
||||
|
||||
typedef struct PEGEN_UnwindInfoList{
|
||||
PEGEN_UnwindInfo *first;
|
||||
PEGEN_UnwindInfo *last;
|
||||
U64 count;
|
||||
} PEGEN_UnwindInfoList;
|
||||
|
||||
typedef struct PEGEN_UnwindBlocks{
|
||||
PEGEN_Block *exception_handlers;
|
||||
PEGEN_Block *unwind_info;
|
||||
} PEGEN_UnwindBlocks;
|
||||
|
||||
////////////////////////////////
|
||||
// PE Generator Functions
|
||||
|
||||
/// gen api ///
|
||||
|
||||
// ctx
|
||||
function PEGEN_Ctx* pegen_begin(void);
|
||||
function void pegen_release(PEGEN_Ctx *gen);
|
||||
|
||||
// data blocks
|
||||
function PEGEN_Block* pegen_block_new(PEGEN_Ctx *gen);
|
||||
function PEGEN_Block* pegen_block_new_write(PEGEN_Ctx *gen, String8 data);
|
||||
function PEGEN_Block* pegen_block_new_aligned(PEGEN_Ctx *gen, U32 align);
|
||||
|
||||
function void*pegen_block_push(PEGEN_Ctx *gen, PEGEN_Block* block, U32 size);
|
||||
function void*pegen_block_push_write(PEGEN_Ctx *gen, PEGEN_Block* block, String8 data);
|
||||
function U8* pegen_block_push_cstring(PEGEN_Ctx *gen, PEGEN_Block* block, String8 string);
|
||||
|
||||
#define pegen_block_push_array(gen,block,T,c) (T*)pegen_block_push((gen),(block),sizeof(T)*(c))
|
||||
|
||||
function void pegen_block_align(PEGEN_Ctx *gen, PEGEN_Block* block, U8 fillbyte, U32 align);
|
||||
function void pegen_block_fill_to_size(PEGEN_Ctx *gen, PEGEN_Block *block, U8 fillbyte, U32 target_size);
|
||||
|
||||
function void pegen_block_push_block(PEGEN_Ctx *gen, PEGEN_Block *list, PEGEN_Block *block);
|
||||
|
||||
function U32 pegen_block_get_size(PEGEN_Block* block);
|
||||
function String8 pegen_block_flatten(Arena *arena, PEGEN_Block *block);
|
||||
function void pegen_block_flatten__recursive(PEGEN_Block *block, U8 *dst);
|
||||
|
||||
function U32 pegen_block_off_relative_to_ancestor(PEGEN_Block *block, PEGEN_Block *ancestor);
|
||||
|
||||
// labels
|
||||
function PEGEN_Label pegen_label(PEGEN_Ctx *gen, PEGEN_Block *block, U32 off);
|
||||
function PEGEN_Label pegen_label_from_pointer(PEGEN_Ctx *gen, void *ptr);
|
||||
function void* pegen_pointer_from_block_off(PEGEN_Ctx *gen, PEGEN_Block *block, U32 off);
|
||||
function void* pegen_pointer_from_label(PEGEN_Ctx *gen, PEGEN_Label label);
|
||||
|
||||
// patches
|
||||
function PEGEN_PatchList* pegen_patch_list_new(PEGEN_Ctx *gen);
|
||||
|
||||
function PEGEN_Patch* pegen_patch_push(PEGEN_Ctx *gen, PEGEN_PatchList *list);
|
||||
|
||||
function void pegen_patch_foff32_label(PEGEN_Ctx *gen, PEGEN_PatchList *list, void *patchpos_ptr, PEGEN_Label targetpos);
|
||||
|
||||
function void pegen_patch_voff32_label(PEGEN_Ctx *gen, PEGEN_PatchList *list, void *patchpos_ptr, PEGEN_Label targetpos);
|
||||
function void pegen_patch_voff32(PEGEN_Ctx *gen, PEGEN_PatchList *list, void *patchpos_ptr, void *targetpos_ptr);
|
||||
|
||||
function void pegen_patch_vrel32_label(PEGEN_Ctx *gen, PEGEN_PatchList *list, PEGEN_Label patchpos, PEGEN_Label targetpos, S8 bias);
|
||||
|
||||
function void pegen_patch_vaddr64_label(PEGEN_Ctx *gen, PEGEN_PatchList *list, PEGEN_Label patchpos, PEGEN_Label targetpos);
|
||||
|
||||
function void pegen_patch_secnum16(PEGEN_Ctx *gen, PEGEN_PatchList *list, void *patchpos_ptr, PEGEN_Label targetpos);
|
||||
function void pegen_patch_secoff32(PEGEN_Ctx *gen, PEGEN_PatchList *list, void *patchpos_ptr, PEGEN_Label targetpos);
|
||||
|
||||
function void pegen_data_apply_patches(PEGEN_Ctx *gen, U8 *data, U64 size, PEGEN_Block *block, PEGEN_Layout *layout, PEGEN_PatchList *patch_list);
|
||||
|
||||
// sections
|
||||
function PEGEN_SectionList* pegen_section_list_new(PEGEN_Ctx *gen);
|
||||
|
||||
function PEGEN_Section*
|
||||
pegen_section_push(PEGEN_Ctx *gen, PEGEN_SectionList *list,
|
||||
String8 name, PE_SectionFlags flags, U32 vsize,
|
||||
PEGEN_Block *block);
|
||||
|
||||
function void
|
||||
pegen_section_equip_coff_relocs(PEGEN_Section *section,
|
||||
PEGEN_CoffRelocList *list);
|
||||
|
||||
#define PEGEN_DefaultVSize (~((U32)0))
|
||||
|
||||
// image config
|
||||
function PEGEN_ImgConfig* pegen_img_config_new(PEGEN_Ctx *gen);
|
||||
|
||||
function void pegen_img_config_base_vaddr(PEGEN_Ctx *gen, PEGEN_ImgConfig *config, U64 base_vaddr);
|
||||
function void pegen_img_config_file_align(PEGEN_Ctx *gen, PEGEN_ImgConfig *config, U32 file_align);
|
||||
function void pegen_img_config_virt_align(PEGEN_Ctx *gen, PEGEN_ImgConfig *config, U32 virt_align);
|
||||
function void pegen_img_config_entry_point(PEGEN_Ctx *gen, PEGEN_ImgConfig *config, PEGEN_Label label);
|
||||
function void pegen_img_config_data_directory(PEGEN_Ctx *gen, PEGEN_ImgConfig *config,
|
||||
PE_DataDirectoryIdx idx, PEGEN_Block *block);
|
||||
|
||||
// object config
|
||||
function PEGEN_ObjConfig* pegen_obj_config_new(PEGEN_Ctx *gen);
|
||||
|
||||
function void pegen_obj_config_symbol_table(PEGEN_Ctx *gen, PEGEN_ObjConfig *config,
|
||||
PEGEN_SymbolTableBaked *table);
|
||||
|
||||
// headers & layouts
|
||||
function PEGEN_HeaderAndLayout
|
||||
pegen_img_header_bake(PEGEN_Ctx *gen, PEGEN_PatchList *patch_list,
|
||||
PEGEN_SectionList *section_list,
|
||||
PEGEN_ImgConfig *img_config);
|
||||
|
||||
function PEGEN_HeaderAndLayout
|
||||
pegen_obj_header_bake(PEGEN_Ctx *gen, PEGEN_PatchList *patch_list,
|
||||
PEGEN_SectionList *section_list,
|
||||
PEGEN_ObjConfig *obj_config);
|
||||
|
||||
function U32 pegen_layout_voff_from_foff(PEGEN_Layout *layout, U32 foff);
|
||||
function U32 pegen_layout_secnum_from_foff(PEGEN_Layout *layout, U32 foff);
|
||||
function U32 pegen_layout_secoff_from_foff(PEGEN_Layout *layout, U32 foff);
|
||||
|
||||
function U32 pegen_layout_voff_from_block(PEGEN_Layout *layout, PEGEN_Block *block);
|
||||
function U32 pegen_layout_voff_from_label(PEGEN_Layout *layout, PEGEN_Label label);
|
||||
|
||||
// symbol table
|
||||
function PEGEN_SymbolTable* pegen_symbol_table_new(PEGEN_Ctx *gen);
|
||||
|
||||
function PEGEN_Symbol* pegen_symbol_push(PEGEN_Ctx *gen, PEGEN_SymbolTable *symbols,
|
||||
String8 name, PE_CoffSymbolStorageClass storage_class,
|
||||
PE_CoffSymbolType type,
|
||||
PEGEN_Label pos);
|
||||
|
||||
function PEGEN_SymbolTableBaked*
|
||||
pegen_block_from_symbol_table(PEGEN_Ctx *gen, PEGEN_PatchList *patch_list,
|
||||
PEGEN_SymbolTable *symbol_table);
|
||||
|
||||
function U32 pegen_symbol_idx_from_ptr(PEGEN_SymbolTableBaked *table,
|
||||
PEGEN_Symbol *symbol);
|
||||
|
||||
// coff relocs
|
||||
function PEGEN_CoffRelocList* pegen_coff_reloc_list_new(PEGEN_Ctx *gen);
|
||||
|
||||
function void pegen_coff_reloc_push(PEGEN_Ctx *gen, PEGEN_CoffRelocList *list,
|
||||
U32 off, PEGEN_Symbol *symbol,
|
||||
PE_CoffRelocationType reloc_type);
|
||||
|
||||
function PEGEN_Block*
|
||||
pegen_block_from_coff_reloc_list(PEGEN_Ctx *gen,
|
||||
PEGEN_SymbolTableBaked *symbol_table,
|
||||
PEGEN_CoffRelocList *list);
|
||||
|
||||
// export table
|
||||
function PEGEN_ExportTable* pegen_export_table_new(PEGEN_Ctx *gen);
|
||||
|
||||
function void pegen_export_table_set_binary_name(PEGEN_Ctx *gen, PEGEN_ExportTable *table, String8 name);
|
||||
function void pegen_export_table_set_time_stamp(PEGEN_Ctx *gen, PEGEN_ExportTable *table, U32 timestamp);
|
||||
function void pegen_export_table_set_version(PEGEN_Ctx *gen, PEGEN_ExportTable *table, U16 major, U16 minor);
|
||||
|
||||
function PEGEN_Export* pegen_export_new(PEGEN_Ctx *gen, PEGEN_ExportTable *table, PEGEN_Label label);
|
||||
function PEGEN_Export* pegen_export_new_fwd(PEGEN_Ctx *gen, PEGEN_ExportTable *table, String8 fwdname);
|
||||
function void pegen_export_add_name(PEGEN_Ctx *gen, PEGEN_ExportTable *table, PEGEN_Export *exp, String8 name);
|
||||
|
||||
function PEGEN_Block* pegen_block_from_exports(PEGEN_Ctx *gen, PEGEN_PatchList *patch_list_out, PEGEN_ExportTable *table);
|
||||
|
||||
// import table
|
||||
function PEGEN_ImportList* pegen_import_list_new(PEGEN_Ctx *gen);
|
||||
|
||||
function PEGEN_ImportTable* pegen_import_table_new(PEGEN_Ctx *gen, PEGEN_ImportList *list,
|
||||
String8 binary_name, U32 time_stamp);
|
||||
|
||||
function void pegen_import_new(PEGEN_Ctx *gen, PEGEN_ImportTable *table,
|
||||
String8 name, U16 ordinal);
|
||||
|
||||
function PEGEN_ImportBlocks pegen_blocks_from_imports(PEGEN_Ctx *gen, PEGEN_PatchList *patch_list, PEGEN_ImportList *imports);
|
||||
|
||||
// base relocations
|
||||
function PEGEN_BaseRelocationList* pegen_base_relocation_list_new(PEGEN_Ctx *gen);
|
||||
function void pegen_base_relocation_new(PEGEN_Ctx *gen, PEGEN_BaseRelocationList *list,
|
||||
PE_BaseRelocationType type, PEGEN_Label label);
|
||||
|
||||
function PEGEN_Block* pegen_block_from_base_relocations(PEGEN_Ctx *gen, PEGEN_Layout *layout, PEGEN_BaseRelocationList *list);
|
||||
|
||||
function S32 pegen_base_relocation_compare(void *a, void *b, void *udata);
|
||||
|
||||
// unwind info
|
||||
function PEGEN_UnwindInfoList* pegen_unwind_info_list_new(PEGEN_Ctx *gen);
|
||||
function PEGEN_UnwindInfo* pegen_unwind_info_push(PEGEN_Ctx *gen, PEGEN_UnwindInfoList *list);
|
||||
function void pegen_unwind_info_code(PEGEN_Ctx *gen, PEGEN_UnwindInfo *handler,
|
||||
U8 offset, U8 opcode, U8 opinfo, U32 x);
|
||||
|
||||
function PEGEN_UnwindBlocks pegen_blocks_from_unwind_info(PEGEN_Ctx *gen, PEGEN_PatchList *patch_list, PEGEN_UnwindInfoList *list);
|
||||
|
||||
#endif //MR4TH_PE_GEN_H
|
||||
|
|
@ -0,0 +1,257 @@
|
|||
/*
|
||||
** PE File Generator Development
|
||||
*/
|
||||
|
||||
#include "mr4th_base.h"
|
||||
#include "mr4th_base.stdio.h"
|
||||
#include "mr4th_keywords.h"
|
||||
|
||||
#include "block/mr4th_block.h"
|
||||
|
||||
#include "mr4th_pe.h"
|
||||
#include "mr4th_pe.gen.h"
|
||||
|
||||
#include "mr4th_base.c"
|
||||
#include "mr4th_pe.c"
|
||||
#include "mr4th_pe.gen.c"
|
||||
|
||||
#include "block/mr4th_block.c"
|
||||
|
||||
////////////////////////////////
|
||||
// Entry Point
|
||||
|
||||
int main(int argc, char **argv){
|
||||
os_main_init(argc, argv);
|
||||
|
||||
PEGEN_Ctx *gen = pegen_begin();
|
||||
|
||||
String8 output_filename = str8_lit("generated.obj");
|
||||
B32 gen_img = 0;
|
||||
|
||||
// time stamp
|
||||
DateTime date = os_now_universal_time();
|
||||
DateTime local_date = os_local_time_from_universal(&date);
|
||||
U32 time_stamp = os_time_stamp_32_from_date_time(&local_date);
|
||||
|
||||
/// loose construction helper ///
|
||||
PEGEN_SectionList *section_list = pegen_section_list_new(gen);
|
||||
PEGEN_PatchList *patch_list = pegen_patch_list_new(gen);
|
||||
PEGEN_UnwindInfoList *unwind_info_list = pegen_unwind_info_list_new(gen);
|
||||
|
||||
|
||||
/// loose construction helper (image) ///
|
||||
PEGEN_ImgConfig *img_config = 0;
|
||||
PEGEN_ExportTable *exports = 0;
|
||||
PEGEN_ImportList *imports = 0;
|
||||
PEGEN_BaseRelocationList *base_relocs = 0;
|
||||
|
||||
if (gen_img){
|
||||
// init img config
|
||||
img_config = pegen_img_config_new(gen);
|
||||
|
||||
// init exports
|
||||
exports = pegen_export_table_new(gen);
|
||||
pegen_export_table_set_binary_name(gen, exports, output_filename);
|
||||
pegen_export_table_set_time_stamp(gen, exports, time_stamp);
|
||||
pegen_export_table_set_version(gen, exports, 0, 0);
|
||||
|
||||
// init imports
|
||||
imports = pegen_import_list_new(gen);
|
||||
#if 0
|
||||
PEGEN_ImportTable *table =
|
||||
pegen_import_table_new(gen, imports, str8_lit("api-ms-win-crt-heap-l1-1-0.dll"), time_stamp);
|
||||
pegen_import_new(gen, table, str8_lit("malloc"), 25);
|
||||
#endif
|
||||
|
||||
// init base relocations
|
||||
base_relocs = pegen_base_relocation_list_new(gen);
|
||||
}
|
||||
|
||||
|
||||
/// loose construction helper (object) ///
|
||||
PEGEN_ObjConfig *obj_config = 0;
|
||||
PEGEN_SymbolTable *symbol_table = 0;
|
||||
|
||||
if (!gen_img){
|
||||
// init obj config
|
||||
obj_config = pegen_obj_config_new(gen);
|
||||
|
||||
// init symbol table
|
||||
symbol_table = pegen_symbol_table_new(gen);
|
||||
}
|
||||
|
||||
// arrange section data
|
||||
{
|
||||
// bake imports
|
||||
PEGEN_ImportBlocks import_blocks = {0};
|
||||
if (gen_img){
|
||||
import_blocks = pegen_blocks_from_imports(gen, patch_list, imports);
|
||||
pegen_img_config_data_directory(gen, img_config,
|
||||
PE_DataDirectoryIdx_ImportTable,
|
||||
import_blocks.directory_table);
|
||||
pegen_img_config_data_directory(gen, img_config,
|
||||
PE_DataDirectoryIdx_IAT,
|
||||
import_blocks.iat);
|
||||
}
|
||||
|
||||
// text & data
|
||||
PEGEN_Block *text_block = pegen_block_new_write(gen, str8(text, sizeof(text)));
|
||||
PEGEN_Section *text_section =
|
||||
pegen_section_push(gen, section_list, str8_lit(".text$mn"),
|
||||
PE_SectionFlag_CNT_CODE |
|
||||
PE_SectionFlag_MEM_EXECUTE |
|
||||
PE_SectionFlag_MEM_READ,
|
||||
PEGEN_DefaultVSize,
|
||||
text_block);
|
||||
|
||||
PEGEN_CoffRelocList *text_relocs = 0;
|
||||
if (!gen_img){
|
||||
text_relocs = pegen_coff_reloc_list_new(gen);
|
||||
pegen_section_equip_coff_relocs(text_section, text_relocs);
|
||||
}
|
||||
|
||||
PEGEN_Block *data_block = pegen_block_new_write(gen, str8(data, sizeof(data)));
|
||||
pegen_section_push(gen, section_list, str8_lit(".data"),
|
||||
PE_SectionFlag_CNT_INITIALIZED_DATA |
|
||||
PE_SectionFlag_MEM_READ |
|
||||
PE_SectionFlag_MEM_WRITE,
|
||||
PEGEN_DefaultVSize,
|
||||
data_block);
|
||||
|
||||
// entry point
|
||||
if (gen_img){
|
||||
PEGEN_Label entry_point = pegen_label(gen, text_block, 0);
|
||||
pegen_img_config_entry_point(gen, img_config, entry_point);
|
||||
}
|
||||
|
||||
// symbol table
|
||||
PEGEN_Symbol *sym_sum_longname = 0;
|
||||
PEGEN_Symbol *sym_variable = 0;
|
||||
|
||||
if (!gen_img){
|
||||
|
||||
{
|
||||
PEGEN_Label pos = pegen_label(gen, text_block, 0);
|
||||
sym_sum_longname =
|
||||
pegen_symbol_push(gen, symbol_table, str8_lit("sum_longname"),
|
||||
PE_CoffSymbolStorageClass_EXTERNAL,
|
||||
(PE_CoffSymbolTypeHi_FUNCTION << 4), pos);
|
||||
}
|
||||
|
||||
{
|
||||
PEGEN_Label pos = pegen_label(gen, data_block, 0);
|
||||
sym_variable =
|
||||
pegen_symbol_push(gen, symbol_table, str8_lit("variable"),
|
||||
PE_CoffSymbolStorageClass_EXTERNAL, 0, pos);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// text coff relocation
|
||||
if (!gen_img){
|
||||
pegen_coff_reloc_push(gen, text_relocs, 9, sym_variable,
|
||||
PE_CoffRelocationType_REL32);
|
||||
}
|
||||
|
||||
// bake exports
|
||||
PEGEN_Block *export_block = 0;
|
||||
if (gen_img){
|
||||
export_block = pegen_block_from_exports(gen, patch_list, exports);
|
||||
pegen_img_config_data_directory(gen, img_config,
|
||||
PE_DataDirectoryIdx_ExportTable,
|
||||
export_block);
|
||||
}
|
||||
|
||||
// bake unwind info
|
||||
PEGEN_UnwindBlocks unwind_blocks = {0};
|
||||
if (gen_img){
|
||||
unwind_blocks = pegen_blocks_from_unwind_info(gen, patch_list, unwind_info_list);
|
||||
pegen_img_config_data_directory(gen, img_config,
|
||||
PE_DataDirectoryIdx_ExceptionTable,
|
||||
unwind_blocks.exception_handlers);
|
||||
}
|
||||
|
||||
// bake symbol table
|
||||
PEGEN_SymbolTableBaked *symbol_table_baked = 0;
|
||||
if (!gen_img){
|
||||
symbol_table_baked =
|
||||
pegen_block_from_symbol_table(gen, patch_list, symbol_table);
|
||||
pegen_obj_config_symbol_table(gen, obj_config, symbol_table_baked);
|
||||
}
|
||||
|
||||
// put exports & imports into rdata
|
||||
if (gen_img){
|
||||
PEGEN_Block *rdata_block = pegen_block_new(gen);
|
||||
pegen_block_push_block(gen, rdata_block, import_blocks.iat);
|
||||
pegen_block_push_block(gen, rdata_block, export_block);
|
||||
pegen_block_push_block(gen, rdata_block, unwind_blocks.unwind_info);
|
||||
pegen_block_push_block(gen, rdata_block, import_blocks.directory_table);
|
||||
pegen_block_push_block(gen, rdata_block, import_blocks.import_data);
|
||||
|
||||
if (pegen_block_get_size(rdata_block) > 0){
|
||||
pegen_section_push(gen, section_list, str8_lit(".rdata"),
|
||||
PE_SectionFlag_CNT_INITIALIZED_DATA |
|
||||
PE_SectionFlag_MEM_READ,
|
||||
PEGEN_DefaultVSize,
|
||||
rdata_block);
|
||||
}
|
||||
}
|
||||
|
||||
// put exception handlers into pdata
|
||||
if (gen_img){
|
||||
if (pegen_block_get_size(unwind_blocks.exception_handlers) > 0){
|
||||
pegen_section_push(gen, section_list, str8_lit(".pdata"),
|
||||
PE_SectionFlag_CNT_INITIALIZED_DATA |
|
||||
PE_SectionFlag_MEM_READ,
|
||||
PEGEN_DefaultVSize,
|
||||
unwind_blocks.exception_handlers);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// header block
|
||||
PEGEN_HeaderAndLayout hdr_layout = {0};
|
||||
if (gen_img){
|
||||
hdr_layout = pegen_img_header_bake(gen, patch_list, section_list, img_config);
|
||||
}
|
||||
else{
|
||||
hdr_layout = pegen_obj_header_bake(gen, patch_list, section_list, obj_config);
|
||||
}
|
||||
|
||||
// assemble file
|
||||
PEGEN_Block *file = pegen_block_new(gen);
|
||||
{
|
||||
pegen_block_push_block(gen, file, hdr_layout.header);
|
||||
|
||||
for (U32 i = 0; i < hdr_layout.layout->section_count; i += 1){
|
||||
PEGEN_LayoutSection *sec = hdr_layout.layout->sections + i;
|
||||
pegen_block_fill_to_size(gen, file, 0, sec->foff);
|
||||
pegen_block_push_block(gen, file, sec->block);
|
||||
|
||||
U32 aligned_up_foff = sec->foff + sec->fsize + sec->fsize_padding;
|
||||
pegen_block_fill_to_size(gen, file, 0, aligned_up_foff);
|
||||
|
||||
if (sec->reloc_block != 0){
|
||||
pegen_block_push_block(gen, file, sec->reloc_block);
|
||||
}
|
||||
}
|
||||
|
||||
if (!gen_img){
|
||||
if (obj_config->symbol_table != 0){
|
||||
pegen_block_push_block(gen, file, obj_config->symbol_table->block);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// render file
|
||||
{
|
||||
Arena *arena = arena_alloc();
|
||||
String8 data = pegen_block_flatten(arena, file);
|
||||
pegen_data_apply_patches(gen, data.str, data.size, file,
|
||||
hdr_layout.layout, patch_list);
|
||||
os_file_write(output_filename, data);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,831 @@
|
|||
#ifndef MR4TH_PE_H
|
||||
#define MR4TH_PE_H
|
||||
|
||||
/*
|
||||
** PE/COFF total layout summary:
|
||||
**
|
||||
** MS-DOS Stub [image only]
|
||||
** *****************
|
||||
** ptr> PE Signature [image only]
|
||||
** COFF Header
|
||||
** Optional Header [image only]
|
||||
** Section Table
|
||||
*/
|
||||
|
||||
////////////////////////////////
|
||||
// Types: COFF / PE
|
||||
|
||||
#pragma pack(push,1)
|
||||
|
||||
// MS-DOS Stub
|
||||
|
||||
// located at offset=0 in valid executables
|
||||
#define PE_MSDOS_MAGIC 0x5A4D
|
||||
|
||||
typedef struct PE_DosHeader{
|
||||
U16 magic;
|
||||
U16 last_page_size;
|
||||
U16 page_count;
|
||||
U16 reloc_count;
|
||||
U16 paragraph_header_size;
|
||||
U16 min_paragraph;
|
||||
U16 max_paragraph;
|
||||
U16 init_ss;
|
||||
U16 init_sp;
|
||||
U16 checksum;
|
||||
U16 init_ip;
|
||||
U16 init_cs;
|
||||
U16 reloc_table_file_off;
|
||||
U16 overlay_number;
|
||||
U16 reserved[4];
|
||||
U16 oem_id;
|
||||
U16 oem_info;
|
||||
U16 reserved2[10];
|
||||
U32 coff_file_offset;
|
||||
} PE_DosHeader;
|
||||
|
||||
// pe signature
|
||||
|
||||
#define PE_SIGNATURE 0x00004550
|
||||
|
||||
// coff header
|
||||
|
||||
#define PE_MachineType_XList(X)\
|
||||
X(UNKNOWN, 0x0)\
|
||||
X(ALPHA, 0x184)\
|
||||
X(ALPHA64, 0x284)\
|
||||
X(AM33, 0x1d3)\
|
||||
X(AMD64, 0x8664)\
|
||||
X(ARM, 0x1c0)\
|
||||
X(ARM64, 0xaa64)\
|
||||
X(ARMNT, 0x1c4)\
|
||||
X(EBC, 0xebc)\
|
||||
X(I386, 0x14c)\
|
||||
X(IA64, 0x200)\
|
||||
X(LOONGARCH32, 0x6232)\
|
||||
X(LOONGARCH64, 0x6264)\
|
||||
X(M32R, 0x9041)\
|
||||
X(MIPS16, 0x266)\
|
||||
X(MIPSFPU, 0x366)\
|
||||
X(MIPSFPU16, 0x466)\
|
||||
X(POWERPC, 0x1f0)\
|
||||
X(POWERPCFP, 0x1f1)\
|
||||
X(R4000, 0x166)\
|
||||
X(RISCV32, 0x5032)\
|
||||
X(RISCV64, 0x5064)\
|
||||
X(RISCV128, 0x5128)\
|
||||
X(SH3, 0x1a2)\
|
||||
X(SH3DSP, 0x1a3)\
|
||||
X(SH4, 0x1a6)\
|
||||
X(SH5, 0x1a8)\
|
||||
X(THUMB, 0x1c2)\
|
||||
X(WCEMIPSV2, 0x169)
|
||||
|
||||
typedef U16 PE_MachineType;
|
||||
enum{
|
||||
#define X(N,C) PE_MachineType_##N = C,
|
||||
PE_MachineType_XList(X)
|
||||
#undef X
|
||||
};
|
||||
|
||||
#define PE_Flags_XList(X)\
|
||||
X(RELOCS_STRIPPED, 0x0001)\
|
||||
X(EXECUTABLE_IMAGE, 0x0002)\
|
||||
X(LINE_NUMS_STRIPPED, 0x0004)\
|
||||
X(LOCAL_SYMS_STRIPPED, 0x0008)\
|
||||
X(AGGRESSIVE_WS_TRIM, 0x0010)\
|
||||
X(LARGE_ADDRESS_AWARE, 0x0020)\
|
||||
X(RESERVED, 0x0040)\
|
||||
X(BYTES_REVERSED_LO, 0x0080)\
|
||||
X(32BIT_MACHINE, 0x0100)\
|
||||
X(DEBUG_STRIPPED, 0x0200)\
|
||||
X(REMOVABLE_RUN_FROM_SWAP, 0x0400)\
|
||||
X(NET_RUN_FROM_SWAP, 0x0800)\
|
||||
X(SYSTEM, 0x1000)\
|
||||
X(DLL, 0x2000)\
|
||||
X(UP_SYSTEM_ONLY, 0x4000)\
|
||||
X(BYTES_REVERSED_HI, 0x8000)\
|
||||
|
||||
typedef U16 PE_Flags;
|
||||
enum{
|
||||
#define X(N,C) PE_Flag_##N = C,
|
||||
PE_Flags_XList(X)
|
||||
#undef X
|
||||
};
|
||||
|
||||
typedef struct PE_CoffHeader{
|
||||
PE_MachineType machine_type;
|
||||
U16 section_count;
|
||||
U32 time_stamp;
|
||||
U32 symbol_table_foff;
|
||||
U32 symbol_count;
|
||||
U16 optional_header_size;
|
||||
PE_Flags flags;
|
||||
} PE_CoffHeader;
|
||||
|
||||
// optional headers
|
||||
|
||||
#define PE_OptionalHeaderMagic_XList(X)\
|
||||
X(ROM, 0x107)\
|
||||
X(PE32, 0x10B)\
|
||||
X(PE32Plus, 0x20B)
|
||||
|
||||
typedef U16 PE_OptionalHeaderMagic;
|
||||
enum{
|
||||
#define X(N,C) PE_OptionalHeaderMagic_##N = C,
|
||||
PE_OptionalHeaderMagic_XList(X)
|
||||
#undef X
|
||||
};
|
||||
|
||||
#define PE_WindowsSubsystem_XList(X)\
|
||||
X(UNKNOWN, 0)\
|
||||
X(NATIVE, 1)\
|
||||
X(WINDOWS_GUI, 2)\
|
||||
X(WINDOWS_CUI, 3)\
|
||||
X(OS2_CUI, 5)\
|
||||
X(POSIX_CUI, 7)\
|
||||
X(NATIVE_WINDOWS, 8)\
|
||||
X(WINDOWS_CE_GUI, 9)\
|
||||
X(EFI_APPLICATION, 10)\
|
||||
X(EFI_BOOT_SERVICE_DRIVER, 11)\
|
||||
X(EFI_RUNTIME_DRIVER, 12)\
|
||||
X(EFI_ROM, 13)\
|
||||
X(XBOX, 14)\
|
||||
X(WINDOWS_BOOT_APPLICATION, 16)
|
||||
|
||||
typedef U16 PE_WindowsSubsystem;
|
||||
enum{
|
||||
#define X(N,C) PE_WindowsSubsystem_##N = C,
|
||||
PE_WindowsSubsystem_XList(X)
|
||||
#undef X
|
||||
};
|
||||
|
||||
#define PE_DLLFlags_XList(X)\
|
||||
X(RESERVED0, 0x0001)\
|
||||
X(RESERVED1, 0x0002)\
|
||||
X(RESERVED2, 0x0004)\
|
||||
X(RESERVED3, 0x0008)\
|
||||
X(HIGH_ENTROPY_VA, 0x0020)\
|
||||
X(DYNAMIC_BASE, 0x0040)\
|
||||
X(FORCE_INTEGRITY, 0x0080)\
|
||||
X(NX_COMPAT, 0x0100)\
|
||||
X(NO_ISOLATION, 0x0200)\
|
||||
X(NO_SEH, 0x0400)\
|
||||
X(NO_BIND, 0x0800)\
|
||||
X(APPCONTAINER, 0x1000)\
|
||||
X(WDM_DRIVER, 0x2000)\
|
||||
X(GUARD_CF, 0x4000)\
|
||||
X(TERMINAL_SERVER_AWARE, 0x8000)
|
||||
|
||||
typedef U16 PE_DLLFlags;
|
||||
enum{
|
||||
#define X(N,C) PE_DLLFlag_##N = C,
|
||||
PE_DLLFlags_XList(X)
|
||||
#undef X
|
||||
};
|
||||
|
||||
typedef struct PE_OptionalHeader32{
|
||||
PE_OptionalHeaderMagic magic;
|
||||
U8 linker_version_major;
|
||||
U8 linker_version_minor;
|
||||
U32 total_size_text; // 'text' means executable code here
|
||||
U32 total_size_inited_data;
|
||||
U32 total_size_zeroed_data;
|
||||
U32 entry_point_voff;
|
||||
U32 text_voff;
|
||||
U32 data_voff;
|
||||
U32 image_base_vaddr;
|
||||
U32 section_alignment;
|
||||
U32 file_alignment;
|
||||
U16 os_version_major;
|
||||
U16 os_version_minor;
|
||||
U16 image_version_major;
|
||||
U16 image_version_minor;
|
||||
U16 subsystem_version_major;
|
||||
U16 subsystem_version_minor;
|
||||
U32 reserved0;
|
||||
U32 image_size;
|
||||
U32 headers_size;
|
||||
U32 checksum;
|
||||
PE_WindowsSubsystem subsystem;
|
||||
PE_DLLFlags dll_flags;
|
||||
U32 stack_size_reserve;
|
||||
U32 stack_size_commit;
|
||||
U32 heap_size_reserve;
|
||||
U32 heap_size_commit;
|
||||
U32 reserved1;
|
||||
U32 data_directory_count;
|
||||
} PE_OptionalHeader32;
|
||||
|
||||
typedef struct PE_OptionalHeader32Plus{
|
||||
U16 magic;
|
||||
U8 linker_version_major;
|
||||
U8 linker_version_minor;
|
||||
U32 total_size_text; // 'text' means executable code here
|
||||
U32 total_size_inited_data;
|
||||
U32 total_size_zeroed_data;
|
||||
U32 entry_point_voff;
|
||||
U32 text_voff;
|
||||
U64 image_base_vaddr;
|
||||
U32 section_alignment;
|
||||
U32 file_alignment;
|
||||
U16 os_version_major;
|
||||
U16 os_version_minor;
|
||||
U16 image_version_major;
|
||||
U16 image_version_minor;
|
||||
U16 subsystem_version_major;
|
||||
U16 subsystem_version_minor;
|
||||
U32 reserved0;
|
||||
U32 image_size;
|
||||
U32 headers_size;
|
||||
U32 checksum;
|
||||
PE_WindowsSubsystem subsystem;
|
||||
PE_DLLFlags dll_flags;
|
||||
U64 stack_size_reserve;
|
||||
U64 stack_size_commit;
|
||||
U64 heap_size_reserve;
|
||||
U64 heap_size_commit;
|
||||
U32 reserved1;
|
||||
U32 data_directory_count;
|
||||
} PE_OptionalHeader32Plus;
|
||||
|
||||
typedef struct PE_DataDirectory{
|
||||
U32 voff;
|
||||
U32 size;
|
||||
} PE_DataDirectory;
|
||||
|
||||
#define PE_DataDirectoryIdx_XList(X)\
|
||||
X(ExportTable, "Export Table", 0)\
|
||||
X(ImportTable, "Import Table", 1)\
|
||||
X(ResourceTable, "Resource Table", 2)\
|
||||
X(ExceptionTable, "Exception Table", 3)\
|
||||
X(CertificateTable, "Certificate Table", 4)\
|
||||
X(BaseRelocationTable, "Base Relocation Table", 5)\
|
||||
X(Debug, "Debug Directories", 6)\
|
||||
X(Architecture, "Architecture", 7)\
|
||||
X(GlobalPtr, "Global Ptr", 8)\
|
||||
X(TLSTable, "TLS Table", 9)\
|
||||
X(LoadConfigTable, "Load Config Table", 10)\
|
||||
X(BoundImport, "Bound Import", 11)\
|
||||
X(IAT, "IAT", 12)\
|
||||
X(DelayImportDescriptor, "Delay Import Descriptor", 13)\
|
||||
X(CLRRuntimeHeader, "CLR Runtime Header", 14)\
|
||||
X(Reserved, "Reserved", 15)
|
||||
|
||||
typedef U32 PE_DataDirectoryIdx;
|
||||
enum{
|
||||
#define X(N,D,C) PE_DataDirectoryIdx_##N = C,
|
||||
PE_DataDirectoryIdx_XList(X)
|
||||
#undef X
|
||||
PE_DataDirectoryIdx_COUNT
|
||||
};
|
||||
|
||||
// section table
|
||||
|
||||
#define PE_SectionFlags_XList(X)\
|
||||
X(TYPE_NO_PAD, 0x00000008)\
|
||||
X(CNT_CODE, 0x00000020)\
|
||||
X(CNT_INITIALIZED_DATA, 0x00000040)\
|
||||
X(CNT_UNINITIALIZED_DATA, 0x00000080)\
|
||||
X(LNK_OTHER, 0x00000100)\
|
||||
X(LNK_INFO, 0x00000200)\
|
||||
X(LNK_REMOVE, 0x00000800)\
|
||||
X(LNK_COMDAT, 0x00001000)\
|
||||
X(GPREL, 0x00008000)\
|
||||
X(MEM_16BIT, 0x00020000)\
|
||||
X(MEM_LOCKED, 0x00040000)\
|
||||
X(MEM_PRELOAD, 0x00080000)\
|
||||
X(LNK_NRELOC_OVFL, 0x01000000)\
|
||||
X(MEM_DISCARDABLE, 0x02000000)\
|
||||
X(MEM_NOT_CACHED, 0x04000000)\
|
||||
X(MEM_NOT_PAGED, 0x08000000)\
|
||||
X(MEM_SHARED, 0x10000000)\
|
||||
X(MEM_EXECUTE, 0x20000000)\
|
||||
X(MEM_READ, 0x40000000)\
|
||||
X(MEM_WRITE, 0x80000000)
|
||||
|
||||
#define PE_SectionAlignFromSectionFlags(f) ((f)&0x00F00000)
|
||||
|
||||
#define PE_SectionAlign_XList(X)\
|
||||
X(1, 0x00100000)\
|
||||
X(2, 0x00200000)\
|
||||
X(4, 0x00300000)\
|
||||
X(8, 0x00400000)\
|
||||
X(16, 0x00500000)\
|
||||
X(32, 0x00600000)\
|
||||
X(64, 0x00700000)\
|
||||
X(128, 0x00800000)\
|
||||
X(256, 0x00900000)\
|
||||
X(512, 0x00A00000)\
|
||||
X(1024, 0x00B00000)\
|
||||
X(2048, 0x00C00000)\
|
||||
X(4096, 0x00D00000)\
|
||||
X(8192, 0x00E00000)
|
||||
|
||||
typedef U32 PE_SectionFlags;
|
||||
enum{
|
||||
#define X(N,C) PE_SectionFlag_##N = C,
|
||||
PE_SectionFlags_XList(X)
|
||||
#undef X
|
||||
|
||||
#define X(N,C) PE_SectionAlign_##N = C,
|
||||
PE_SectionAlign_XList(X)
|
||||
#undef X
|
||||
};
|
||||
|
||||
typedef struct PE_SectionHeader{
|
||||
U8 name[8];
|
||||
U32 vsize;
|
||||
U32 voff;
|
||||
U32 fsize;
|
||||
U32 foff;
|
||||
U32 relocations_foff;
|
||||
U32 line_numbers_foff;
|
||||
U16 relocation_count;
|
||||
U16 line_number_count;
|
||||
PE_SectionFlags flags;
|
||||
} PE_SectionHeader;
|
||||
|
||||
// coff relocations
|
||||
|
||||
// TODO(allen): these are just the "x64" values
|
||||
// generalize PE_CoffRelocationType to all machines
|
||||
#define PE_CoffRelocationType_XList(X)\
|
||||
X(ABSOLUTE, 0x0000)\
|
||||
X(ADDR64, 0x0001)\
|
||||
X(ADDR32, 0x0002)\
|
||||
X(ADDR32NB, 0x0003)\
|
||||
X(REL32, 0x0004)\
|
||||
X(REL32_1, 0x0005)\
|
||||
X(REL32_2, 0x0006)\
|
||||
X(REL32_3, 0x0007)\
|
||||
X(REL32_4, 0x0008)\
|
||||
X(REL32_5, 0x0009)\
|
||||
X(SECTION, 0x000A)\
|
||||
X(SECREL, 0x000B)\
|
||||
X(SECREL7, 0x000C)\
|
||||
X(TOKEN, 0x000D)\
|
||||
X(SREL32, 0x000E)\
|
||||
X(PAIR, 0x000F)\
|
||||
X(SSPAN32, 0x0010)
|
||||
|
||||
typedef U16 PE_CoffRelocationType;
|
||||
enum{
|
||||
#define X(N,C) PE_CoffRelocationType_##N = C,
|
||||
PE_CoffRelocationType_XList(X)
|
||||
#undef X
|
||||
};
|
||||
|
||||
typedef struct PE_CoffRelocation{
|
||||
U32 off;
|
||||
U32 symbol_idx;
|
||||
PE_CoffRelocationType type;
|
||||
} PE_CoffRelocation;
|
||||
|
||||
// coff symbol table
|
||||
|
||||
#define PE_CoffSymbolStorageClass_XList(X)\
|
||||
X(END_OF_FUNCTION, 0xFF)\
|
||||
X(NULL, 0)\
|
||||
X(AUTOMATIC, 1)\
|
||||
X(EXTERNAL, 2)\
|
||||
X(STATIC, 3)\
|
||||
X(REGISTER, 4)\
|
||||
X(EXTERNAL_DEF, 5)\
|
||||
X(LABEL, 6)\
|
||||
X(UNDEFINED_LABEL, 7)\
|
||||
X(MEMBER_OF_STRUCT, 8)\
|
||||
X(ARGUMENT, 9)\
|
||||
X(STRUCT_TAG, 10)\
|
||||
X(MEMBER_OF_UNION, 11)\
|
||||
X(UNION_TAG, 12)\
|
||||
X(TYPE_DEFINITION, 13)\
|
||||
X(UNDEFINED_STATIC, 14)\
|
||||
X(ENUM_TAG, 15)\
|
||||
X(MEMBER_OF_ENUM, 16)\
|
||||
X(REGISTER_PARAM, 17)\
|
||||
X(BIT_FIELD, 18)\
|
||||
X(BLOCK, 100)\
|
||||
X(FUNCTION, 101)\
|
||||
X(END_OF_STRUCT, 102)\
|
||||
X(FILE, 103)\
|
||||
X(SECTION, 104)\
|
||||
X(WEAK_EXTERNAL, 105)\
|
||||
X(CLR_TOKEN, 107)
|
||||
|
||||
typedef U8 PE_CoffSymbolStorageClass;
|
||||
enum{
|
||||
#define X(N,C) PE_CoffSymbolStorageClass_##N = C,
|
||||
PE_CoffSymbolStorageClass_XList(X)
|
||||
#undef X
|
||||
};
|
||||
|
||||
#define PE_CoffSymbolTypeLo_XList(X)\
|
||||
X(NULL, 0)\
|
||||
X(VOID, 1)\
|
||||
X(CHAR, 2)\
|
||||
X(SHORT, 3)\
|
||||
X(INT, 4)\
|
||||
X(LONG, 5)\
|
||||
X(FLOAT, 6)\
|
||||
X(DOUBLE, 7)\
|
||||
X(STRUCT, 8)\
|
||||
X(UNION, 9)\
|
||||
X(ENUM, 10)\
|
||||
X(MOE, 11)\
|
||||
X(BYTE, 12)\
|
||||
X(WORD, 13)\
|
||||
X(UINT, 14)\
|
||||
X(DWORD, 15)
|
||||
|
||||
enum{
|
||||
#define X(N,C) PE_CoffSymbolTypeLo_##N = C,
|
||||
PE_CoffSymbolTypeLo_XList(X)
|
||||
#undef X
|
||||
};
|
||||
|
||||
#define PE_CoffSymbolTypeHi_XList(X)\
|
||||
X(NULL, 0)\
|
||||
X(POINTER, 1)\
|
||||
X(FUNCTION, 2)\
|
||||
X(ARRAY, 3)
|
||||
|
||||
enum{
|
||||
#define X(N,C) PE_CoffSymbolTypeHi_##N = C,
|
||||
PE_CoffSymbolTypeHi_XList(X)
|
||||
#undef X
|
||||
};
|
||||
|
||||
typedef U16 PE_CoffSymbolType;
|
||||
|
||||
typedef struct PE_CoffSymbolRecord{
|
||||
union{
|
||||
U8 raw[8];
|
||||
struct{
|
||||
U32 zero;
|
||||
U32 string_table_off;
|
||||
};
|
||||
} name;
|
||||
U32 val;
|
||||
S16 sec_number;
|
||||
PE_CoffSymbolType type;
|
||||
PE_CoffSymbolStorageClass storage_class;
|
||||
U8 aux_symbol_count;
|
||||
} PE_CoffSymbolRecord;
|
||||
|
||||
// TODO(allen): COFF Line Numbers (Deprecated)
|
||||
|
||||
// TODO(allen): Attribute Certificate Table
|
||||
|
||||
// TODO(allen): Delay-Load Import Tables
|
||||
|
||||
// export data
|
||||
|
||||
typedef struct PE_ExportDirectoryTable{
|
||||
U32 reserved0;
|
||||
U32 time_stamp;
|
||||
U16 version_major;
|
||||
U16 version_minor;
|
||||
U32 binary_name_voff;
|
||||
U32 ordinal_base;
|
||||
U32 export_count;
|
||||
U32 ordinal_count;
|
||||
U32 export_voff;
|
||||
U32 name_voff;
|
||||
U32 ordinal_voff;
|
||||
|
||||
/*
|
||||
** NOTE(allen): Additional Structure Information
|
||||
** export : [ export_count] U32;
|
||||
** name : [ordinal_count] U32;
|
||||
** ordinal : [ordinal_count] U16;
|
||||
**
|
||||
** for i in [0,ordinal_count):
|
||||
** name[i] : voff to a cstring
|
||||
** export[ordinal[i]] : voff to a symbol OR voff to forwarding string
|
||||
** (voffs in export range are fowarding strings)
|
||||
** ordinal[i] : "unbiased ordinal"
|
||||
** ordinal[i] + ordinal_base : "ordinal"
|
||||
*/
|
||||
|
||||
} PE_ExportDirectoryTable;
|
||||
|
||||
// import data
|
||||
|
||||
typedef struct PE_ImportDirectoryTable{
|
||||
U32 import_lookup_table_voff;
|
||||
U32 time_stamp;
|
||||
U32 first_forwarder_idx;
|
||||
U32 name_voff;
|
||||
U32 import_address_table_voff;
|
||||
|
||||
/*
|
||||
** NOTE(allen): Additional Structure Information
|
||||
** IF PE32:
|
||||
** import_lookup_table : null-terminated [] U32;
|
||||
** IF PE32Plus:
|
||||
** import_lookup_table : null-terminated [] U64;
|
||||
**
|
||||
** WHEN lookup = import_lookup_table[i]
|
||||
** if (HighBits1(lookup)){
|
||||
** ordinal = LowBits16(lookup)
|
||||
** }
|
||||
** else{
|
||||
** hint_voff = LowBits31(lookup)
|
||||
** hint : { U16, null-terminated-cstring }
|
||||
** }
|
||||
*/
|
||||
|
||||
} PE_ImportDirectoryTable;
|
||||
|
||||
// exception handling
|
||||
|
||||
#if 0
|
||||
// NOTE(allen): untested - from documentation
|
||||
typedef struct PE_ExceptionHandler_MIPS{
|
||||
U32 begin_vaddr;
|
||||
U32 end_vaddr;
|
||||
U32 handler_vaddr;
|
||||
U32 handler_data;
|
||||
U32 prolog_end_vaddr;
|
||||
} PE_ExceptionHandler_MIPS;
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
// NOTE(allen): untested - from documentation
|
||||
typedef struct PE_ExceptionHandler_ARM{
|
||||
U32 begin_vaddr;
|
||||
U32 info;
|
||||
} PE_ExceptionHandler_ARM;
|
||||
|
||||
#define PE_ExceptionHandler_ARMInfo_PrologLength(i) (((i) >> 0)&0xFF)
|
||||
#define PE_ExceptionHandler_ARMInfo_FuncLength(i) (((i) >> 8)&0x3FFFFF)
|
||||
#define PE_ExceptionHandler_ARMInfo_32Bit(i) (((i) >> 30)&0x1)
|
||||
#define PE_ExceptionHandler_ARMInfo_ExceptionFlag(i) (((i) >> 31)&0x1)
|
||||
#endif
|
||||
|
||||
typedef struct PE_ExceptionHandler_X86{
|
||||
U32 begin_voff;
|
||||
U32 end_voff;
|
||||
U32 unwind_voff;
|
||||
} PE_ExceptionHandler_X86;
|
||||
|
||||
typedef struct PE_UnwindInfo{
|
||||
U8 header;
|
||||
U8 prolog_size;
|
||||
U8 code_count;
|
||||
U8 frame;
|
||||
} PE_UnwindInfo;
|
||||
|
||||
#define PE_UnwindInfo_VersionFromHeader(x) ((x)&7)
|
||||
#define PE_UnwindInfo_FlagsFromHeader(x) (((x)>>3)&0x1F)
|
||||
|
||||
#define PE_UnwindInfoFlags_XList(X)\
|
||||
X(EHANDLER, (1 << 0))\
|
||||
X(UHANDLER, (1 << 1))\
|
||||
X(CHAINED, (1 << 2))
|
||||
|
||||
typedef U8 PE_UnwindInfoFlags;
|
||||
enum{
|
||||
#define X(N,C) PE_UnwindInfoFlag_##N = C,
|
||||
PE_UnwindInfoFlags_XList(X)
|
||||
#undef X
|
||||
};
|
||||
|
||||
#define PE_UnwindInfo_RegFromFrame(x) ((x)&0xF)
|
||||
#define PE_UnwindInfo_OffFromFrame(x) (((x) >> 4)&0xF)
|
||||
|
||||
#define PE_UnwindOpCode_XList(X)\
|
||||
X(PUSH_NONVOL, 0)\
|
||||
X(ALLOC_LARGE, 1)\
|
||||
X(ALLOC_SMALL, 2)\
|
||||
X(SET_FPREG, 3)\
|
||||
X(SAVE_NONVOL, 4)\
|
||||
X(SAVE_NONVOL_FAR, 5)\
|
||||
X(EPILOG, 6)\
|
||||
X(SPARE, 7)\
|
||||
X(SAVE_XMM128, 8)\
|
||||
X(SAVE_XMM128_FAR, 9)\
|
||||
X(PUSH_MACHFRAME, 10)
|
||||
|
||||
typedef U8 PE_UnwindOpCode;
|
||||
enum{
|
||||
#define X(N,C) PE_UnwindOpCode_##N = C,
|
||||
PE_UnwindOpCode_XList(X)
|
||||
#undef X
|
||||
};
|
||||
|
||||
#define PE_UnwindCode_GetOffset(x) (((x) >> 0)&0xFF)
|
||||
#define PE_UnwindCode_GetOpCode(x) (((x) >> 8)&0x0F)
|
||||
#define PE_UnwindCode_GetOpInfo(x) (((x) >> 12)&0x0F)
|
||||
|
||||
#define PE_UnwindCode_FromOffsetOpCodeInfo(off,opcode,opinfo) \
|
||||
(((off)&0xFF) | (((opcode)&0xF) << 8) | (((opinfo)&0xF) << 12))
|
||||
|
||||
#define PE_UnwindRegX64_XList(X)\
|
||||
X(RAX, 0)\
|
||||
X(RCX, 1)\
|
||||
X(RDX, 2)\
|
||||
X(RBX, 3)\
|
||||
X(RSP, 4)\
|
||||
X(RBP, 5)\
|
||||
X(RSI, 6)\
|
||||
X(RDI, 7)\
|
||||
X(R8, 8)\
|
||||
X(R9, 9)\
|
||||
X(R10, 10)\
|
||||
X(R11, 11)\
|
||||
X(R12, 12)\
|
||||
X(R13, 13)\
|
||||
X(R14, 14)\
|
||||
X(R15, 15)
|
||||
|
||||
typedef U8 PE_UnwindRegX64;
|
||||
enum{
|
||||
#define X(N,C) PE_UnwindRegX64_##N = C,
|
||||
PE_UnwindRegX64_XList(X)
|
||||
#undef X
|
||||
};
|
||||
|
||||
// base relocations
|
||||
|
||||
typedef struct PE_BaseRelocationBlock{
|
||||
U32 page_voff;
|
||||
U32 block_size;
|
||||
} PE_BaseRelocationBlock;
|
||||
|
||||
typedef U16 PE_BaseRelocationTypeOffset;
|
||||
|
||||
#define PE_BaseRelocationType_XList(X)\
|
||||
X(ABSOLUTE, 0)\
|
||||
X(HIGH, 1)\
|
||||
X(LOW, 2)\
|
||||
X(HIGHLOW, 3)\
|
||||
X(HIGHADJ, 4)\
|
||||
X(SPLIT1, 5)\
|
||||
X(SPLIT2, 7)\
|
||||
X(SPLIT3, 8)\
|
||||
X(MIPS_JMPADDR16, 9)\
|
||||
X(DIR64, 10)
|
||||
|
||||
typedef U8 PE_BaseRelocationType;
|
||||
enum{
|
||||
#define X(N,C) PE_BaseRelocationType_##N = C,
|
||||
PE_BaseRelocationType_XList(X)
|
||||
#undef X
|
||||
};
|
||||
|
||||
// SPLIT1: MIPS -> JMPADDR, ARM -> MOV32, RISCV -> HIGH20
|
||||
// SPLIT2: THUMB -> MOV32, RISCV -> LOW12I
|
||||
// SPLIT3: RISCV -> LOW12S, LOONGARCH32 -> MARK_LA, LOONGARCH64 -> MARK_LA
|
||||
|
||||
#define PE_BaseRelocationTypeOffset_GetType(X) (((X) >> 12)&0xF)
|
||||
#define PE_BaseRelocationTypeOffset_GetOff(X) (((X) >> 0)&0xFFF)
|
||||
|
||||
// debug
|
||||
|
||||
#define PE_DebugType_XList(X)\
|
||||
X(UNKNOWN, 0)\
|
||||
X(COFF, 1)\
|
||||
X(CODEVIEW, 2)\
|
||||
X(FPO, 3)\
|
||||
X(MISC, 4)\
|
||||
X(EXCEPTION, 5)\
|
||||
X(OMAP_TO_SRC, 7)\
|
||||
X(OMAP_FROM_SRC, 8)\
|
||||
X(BORLAND, 9)\
|
||||
X(RESERVED10, 10)\
|
||||
X(CLSID, 11)\
|
||||
X(VC_FEATURE, 12)\
|
||||
X(POGO, 13)\
|
||||
X(ILTCG, 14)\
|
||||
X(MPX, 15)\
|
||||
X(REPRO, 16)\
|
||||
X(EMBEDDED, 17)\
|
||||
X(CRYPTOHASH, 19)\
|
||||
X(EX_DLLCHARACTERISTICS, 20)
|
||||
|
||||
typedef U32 PE_DebugType;
|
||||
enum{
|
||||
#define X(N,C) PE_DebugType_##N = C,
|
||||
PE_DebugType_XList(X)
|
||||
#undef X
|
||||
};
|
||||
|
||||
typedef struct PE_DebugDirectory{
|
||||
U32 reserved0;
|
||||
U32 time_stamp;
|
||||
U16 version_major;
|
||||
U16 version_minor;
|
||||
PE_DebugType type;
|
||||
U32 size;
|
||||
U32 voff;
|
||||
U32 foff;
|
||||
} PE_DebugDirectory;
|
||||
|
||||
/* TODO(allen):
|
||||
** [ ] Can we gather information about debug info types besides CODEVIEW ?
|
||||
** [ ] What are the first 24 bytes of the CODEVIEW data range?
|
||||
*/
|
||||
|
||||
// tls table
|
||||
|
||||
typedef U32 PE_TlsDirectoryFlags;
|
||||
#define PE_TLSDirectoryFlags_GetAlign(X) ((X)&0x00F00000)
|
||||
|
||||
typedef struct PE_TLSDirectory32{
|
||||
U32 raw_data_start_vaddr;
|
||||
U32 raw_data_end_vaddr;
|
||||
U32 tls_index_vaddr;
|
||||
U32 tls_callback_array_vaddr;
|
||||
U32 zero_fill_size;
|
||||
PE_TlsDirectoryFlags flags;
|
||||
} PE_TLSDirectory32;
|
||||
|
||||
typedef struct PE_TLSDirectory32Plus{
|
||||
U64 raw_data_start_vaddr;
|
||||
U64 raw_data_end_vaddr;
|
||||
U64 tls_index_vaddr;
|
||||
U64 tls_callback_array_vaddr;
|
||||
U32 zero_fill_size;
|
||||
PE_TlsDirectoryFlags flags;
|
||||
} PE_TLSDirectory32Plus;
|
||||
|
||||
// load config table
|
||||
|
||||
/* TODO(allen): pneumonics for load config that are missing
|
||||
** [ ] global flags
|
||||
** [ ] process affinity mask
|
||||
** [ ] process heap flags
|
||||
** [ ] control flow guard flags
|
||||
*/
|
||||
|
||||
typedef struct PE_LoadConfig32{
|
||||
U32 reserved0;
|
||||
U32 time_stamp;
|
||||
U16 version_major;
|
||||
U16 version_minor;
|
||||
U32 global_flags_clear;
|
||||
U32 global_flags_set;
|
||||
U32 default_critical_section_timeout;
|
||||
U32 decommit_free_block_threshold;
|
||||
U32 decommit_total_free_threshold;
|
||||
U32 lock_prefix_table_vaddr;
|
||||
U32 maximum_allocation_size;
|
||||
U32 virtual_memory_threshold;
|
||||
U32 process_affinity_mask;
|
||||
U32 process_heap_flags;
|
||||
U16 csd_version;
|
||||
U16 reserved1;
|
||||
U32 reserved2;
|
||||
U32 security_cookie_vaddr;
|
||||
U32 seh_table_vaddr;
|
||||
U32 seh_count;
|
||||
U32 control_flow_guard_check_function_vaddr;
|
||||
U32 control_flow_guard_dispatch_function_vaddr;
|
||||
U32 control_flow_guard_function_table_vaddr;
|
||||
U32 control_flow_guard_function_count;
|
||||
U32 control_flow_guard_flags;
|
||||
U8 code_integrity[12];
|
||||
U32 guard_address_taken_iat_table_vaddr;
|
||||
U32 guard_address_taken_iat_count;
|
||||
U32 guard_long_jump_target_table_vaddr;
|
||||
U32 guard_long_jump_target_count;
|
||||
} PE_LoadConfig32;
|
||||
|
||||
typedef struct PE_LoadConfig64{
|
||||
U32 reserved0;
|
||||
U32 time_stamp;
|
||||
U16 version_major;
|
||||
U16 version_minor;
|
||||
U32 global_flags_clear;
|
||||
U32 global_flags_set;
|
||||
U32 default_critical_section_timeout;
|
||||
U64 decommit_free_block_threshold;
|
||||
U64 decommit_total_free_threshold;
|
||||
U64 lock_prefix_table_vaddr;
|
||||
U64 maximum_allocation_size;
|
||||
U64 virtual_memory_threshold;
|
||||
U64 process_affinity_mask;
|
||||
U32 process_heap_flags;
|
||||
U16 csd_version;
|
||||
U16 reserved1;
|
||||
U64 reserved2;
|
||||
U64 security_cookie_vaddr;
|
||||
U64 seh_table_vaddr;
|
||||
U64 seh_count;
|
||||
U64 control_flow_guard_check_function_vaddr;
|
||||
U64 control_flow_guard_dispatch_function_vaddr;
|
||||
U64 control_flow_guard_function_table_vaddr;
|
||||
U64 control_flow_guard_function_count;
|
||||
U32 control_flow_guard_flags;
|
||||
U8 code_integrity[12];
|
||||
U64 guard_address_taken_iat_table_vaddr;
|
||||
U64 guard_address_taken_iat_count;
|
||||
U64 guard_long_jump_target_table_vaddr;
|
||||
U64 guard_long_jump_target_count;
|
||||
} PE_LoadConfig64;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif //MR4TH_PE_H
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
////////////////////////////////
|
||||
// PE Parse Functions
|
||||
|
||||
static PE_SectionHeader*
|
||||
pe_section_header_from_name(String8 img, String8 name){
|
||||
// extract dos header
|
||||
PE_DosHeader *dos_header = 0;
|
||||
if (sizeof(*dos_header) <= img.size){
|
||||
dos_header = (PE_DosHeader*)(img.str);
|
||||
if (dos_header->magic != PE_MSDOS_MAGIC){
|
||||
dos_header = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// extract coff file offset
|
||||
U32 coff_file_offset = 0;
|
||||
if (dos_header != 0){
|
||||
coff_file_offset = dos_header->coff_file_offset;
|
||||
}
|
||||
|
||||
// extract pe signature
|
||||
U32 pe_signature = 0;
|
||||
U32 coff_header_offset = 0;
|
||||
if (0 < coff_file_offset &&
|
||||
coff_file_offset + sizeof(pe_signature) <= img.size){
|
||||
pe_signature = *(U32*)(img.str + coff_file_offset);
|
||||
if (pe_signature == PE_SIGNATURE){
|
||||
coff_header_offset = coff_file_offset + sizeof(pe_signature);
|
||||
}
|
||||
}
|
||||
|
||||
// extract coff header
|
||||
PE_CoffHeader *coff_header = 0;
|
||||
if (0 < coff_header_offset &&
|
||||
coff_header_offset + sizeof(*coff_header) <= img.size){
|
||||
coff_header = (PE_CoffHeader*)(img.str + coff_header_offset);
|
||||
}
|
||||
|
||||
// extract section table offset & count
|
||||
U32 section_table_offset = 0;
|
||||
U32 section_count = 0;
|
||||
if (coff_header != 0){
|
||||
section_table_offset = ( coff_header_offset
|
||||
+ sizeof(*coff_header)
|
||||
+ coff_header->optional_header_size);
|
||||
section_count = coff_header->section_count;
|
||||
}
|
||||
|
||||
// scan section table
|
||||
PE_SectionHeader *match = 0;
|
||||
if (0 < section_table_offset &&
|
||||
section_table_offset + sizeof(PE_SectionHeader)*section_count <= img.size){
|
||||
PE_SectionHeader *sec = (PE_SectionHeader*)(img.str + section_table_offset);
|
||||
for (U32 i = 0; i < section_count; i += 1, sec += 1){
|
||||
U8 *ptr = sec->name;
|
||||
for (;*ptr != 0 && ptr < sec->name + sizeof(sec->name); ptr += 1);
|
||||
String8 secname = str8(sec->name, ptr - sec->name);
|
||||
if (str8_match(name, secname, 0)){
|
||||
match = sec;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return(match);
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
#ifndef MR4TH_PE_PARSE_H
|
||||
#define MR4TH_PE_PARSE_H
|
||||
|
||||
////////////////////////////////
|
||||
// PE Parse Functions
|
||||
|
||||
static PE_SectionHeader* pe_section_header_from_name(String8 img, String8 name);
|
||||
|
||||
#endif //MR4TH_PE_PARSE_H
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,82 @@
|
|||
#ifndef MR4TH_PE_PARSE_EXAMPLE_H
|
||||
#define MR4TH_PE_PARSE_EXAMPLE_H
|
||||
|
||||
////////////////////////////////
|
||||
// PE Parse Example Arguments Types
|
||||
|
||||
typedef struct PEDUMP_Arguments{
|
||||
String8 input_file_name;
|
||||
} PEDUMP_Arguments;
|
||||
|
||||
////////////////////////////////
|
||||
// PE Parse Example Helper Types
|
||||
|
||||
typedef struct PEDUMP_CoffSymbol{
|
||||
String8 name;
|
||||
U32 val;
|
||||
S16 sec_number;
|
||||
PE_CoffSymbolType type;
|
||||
PE_CoffSymbolStorageClass storage_class;
|
||||
U8 aux_symbol_count;
|
||||
} PEDUMP_CoffSymbol;
|
||||
|
||||
typedef struct PEDUMP_ExportSymbol{
|
||||
U32 voff;
|
||||
String8 fwd;
|
||||
String8 name;
|
||||
} PEDUMP_ExportSymbol;
|
||||
|
||||
typedef struct PEDUMP_ImportSymbol{
|
||||
U16 ordinal;
|
||||
String8 name;
|
||||
} PEDUMP_ImportSymbol;
|
||||
|
||||
typedef struct PEDUMP_ImportTable{
|
||||
struct PEDUMP_ImportTable *next;
|
||||
|
||||
U32 time_stamp;
|
||||
U32 first_forwarder_idx;
|
||||
|
||||
String8 name;
|
||||
|
||||
PEDUMP_ImportSymbol *syms;
|
||||
U64 lookup_count;
|
||||
} PEDUMP_ImportTable;
|
||||
|
||||
typedef struct PEDUMP_BaseRelocation{
|
||||
U32 type;
|
||||
U32 voff;
|
||||
} PEDUMP_BaseRelocation;
|
||||
|
||||
typedef struct PEDUMP_UnwindCode{
|
||||
struct PEDUMP_UnwindCode *next;
|
||||
U8 offset;
|
||||
U8 opcode;
|
||||
U8 opinfo;
|
||||
U8 extra_slot_count;
|
||||
U32 x;
|
||||
} PEDUMP_UnwindCode;
|
||||
|
||||
typedef struct PEDUMP_UnwindInfo{
|
||||
U8 version;
|
||||
U8 flags;
|
||||
U8 prolog_size;
|
||||
U8 code_slot_count;
|
||||
U8 code_count;
|
||||
U8 frame_reg;
|
||||
U8 frame_off;
|
||||
PEDUMP_UnwindCode *first_code;
|
||||
PEDUMP_UnwindCode *last_code;
|
||||
} PEDUMP_UnwindInfo;
|
||||
|
||||
////////////////////////////////
|
||||
// PE Parse Example Arguments Functions
|
||||
|
||||
function PEDUMP_Arguments* pedump_args(Arena *arena, String8List *args);
|
||||
|
||||
////////////////////////////////
|
||||
// Entry Point
|
||||
|
||||
int main(int argc, char **argv);
|
||||
|
||||
#endif //MR4TH_PE_PARSE_EXAMPLE_H
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
** PE Tabulator
|
||||
*/
|
||||
|
||||
#include "mr4th_base.h"
|
||||
#include "mr4th_base.stdio.h"
|
||||
#include "mr4th_keywords.h"
|
||||
|
||||
#include "mr4th_pe.h"
|
||||
#include "mr4th_stream.h"
|
||||
#include "mr4th_ascii.h"
|
||||
|
||||
#include "mr4th_pe.table.h"
|
||||
|
||||
#include "mr4th_base.c"
|
||||
#include "mr4th_pe.c"
|
||||
#include "mr4th_stream.c"
|
||||
#include "mr4th_ascii.c"
|
||||
|
||||
////////////////////////////////
|
||||
// PE Tabulator Argument Functions
|
||||
|
||||
function PETAB_Args*
|
||||
petab_args(Arena *arena, String8List *command_line_args){
|
||||
// parse
|
||||
CMDLN *cmdln = cmdln_from_args(arena, command_line_args);
|
||||
|
||||
// setup args
|
||||
PETAB_Args *args = push_array(arena, PETAB_Args, 1);
|
||||
|
||||
// get input file name
|
||||
args->input_file_name = cmdln_input_from_idx(cmdln, 0);
|
||||
|
||||
return(args);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
// Entry Point
|
||||
|
||||
int main(int argc, char **argv){
|
||||
os_main_init(argc, argv);
|
||||
Arena *arena = arena_alloc();
|
||||
|
||||
// arguments
|
||||
String8List command_line_args = os_command_line_arguments();
|
||||
PETAB_Args *args = petab_args(arena, &command_line_args);
|
||||
|
||||
// load input file
|
||||
String8 data = os_file_read(arena, args->input_file_name);
|
||||
|
||||
|
||||
/////////////////
|
||||
///// PARSE /////
|
||||
/////////////////
|
||||
|
||||
// extract dos header
|
||||
PE_DosHeader *dos_header = 0;
|
||||
if (sizeof(*dos_header) <= data.size){
|
||||
dos_header = (PE_DosHeader*)(data.str);
|
||||
if (dos_header->magic != PE_MSDOS_MAGIC){
|
||||
dos_header = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// extract coff file offset
|
||||
U32 coff_file_offset = 0;
|
||||
if (dos_header != 0){
|
||||
coff_file_offset = dos_header->coff_file_offset;
|
||||
}
|
||||
|
||||
// extract pe signature
|
||||
U32 pe_signature = 0;
|
||||
U32 coff_header_offset = 0;
|
||||
if (0 < coff_file_offset &&
|
||||
coff_file_offset + sizeof(pe_signature) <= data.size){
|
||||
pe_signature = *(U32*)(data.str + coff_file_offset);
|
||||
if (pe_signature == PE_SIGNATURE){
|
||||
coff_header_offset = coff_file_offset + sizeof(pe_signature);
|
||||
}
|
||||
}
|
||||
|
||||
// extract coff header
|
||||
PE_CoffHeader *coff_header = 0;
|
||||
U64 coff_header_opl = 0;
|
||||
if (When(dos_header != 0, 0 < coff_header_offset) &&
|
||||
coff_header_offset + sizeof(*coff_header) <= data.size){
|
||||
coff_header = (PE_CoffHeader*)(data.str + coff_header_offset);
|
||||
coff_header_opl = coff_header_offset + sizeof(*coff_header);
|
||||
}
|
||||
|
||||
// optional header
|
||||
U64 optional_header_opl = coff_header_opl;
|
||||
if (coff_header != 0 &&
|
||||
coff_header->optional_header_size > 0){
|
||||
optional_header_opl = coff_header_opl + coff_header->optional_header_size;
|
||||
}
|
||||
|
||||
// determine if this is an image file
|
||||
B32 is_image = (coff_header_offset != 0);
|
||||
|
||||
// parse section table
|
||||
PE_SectionHeader *section_table = 0;
|
||||
U64 section_count = 0;
|
||||
if (coff_header != 0){
|
||||
U64 section_table_offset = optional_header_opl;
|
||||
U64 section_table_opl = section_table_offset + coff_header->section_count*sizeof(PE_SectionHeader);
|
||||
if (section_table_opl <= data.size){
|
||||
section_table = (PE_SectionHeader*)(data.str + section_table_offset);
|
||||
section_count = coff_header->section_count;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/////////////////
|
||||
///// PRINT /////
|
||||
/////////////////
|
||||
|
||||
STREAM *stream = stream_new();
|
||||
STREAM *tempstr = stream_new();
|
||||
|
||||
{
|
||||
TABLE *table = table_begin(arena);
|
||||
|
||||
{
|
||||
table_default_align(table, TABLE_CellFlag_CenterAlign);
|
||||
|
||||
// TODO(allen): conditionals on columns
|
||||
table_row(arena, table);
|
||||
table_cellf(arena, table, "#");
|
||||
table_cellf(arena, table, "Name");
|
||||
table_cellf(arena, table, "V.Size");
|
||||
table_cellf(arena, table, "V.Off");
|
||||
table_cellf(arena, table, "F.Size");
|
||||
table_cellf(arena, table, "F.Off");
|
||||
table_cellf(arena, table, "Mem");
|
||||
table_cellf(arena, table, "#Relocs");
|
||||
table_cellf(arena, table, "#Lines");
|
||||
table_hz_separator(arena, table);
|
||||
|
||||
table_default_align(table, TABLE_CellFlag_LeftAlign);
|
||||
}
|
||||
|
||||
{
|
||||
PE_SectionHeader *sec = section_table;
|
||||
for (U64 i = 0; i < section_count; i += 1, sec += 1){
|
||||
table_row(arena, table);
|
||||
|
||||
table_cellf(arena, table, "%u", i + 1);
|
||||
table_cell_align(table, TABLE_CellFlag_RightAlign);
|
||||
|
||||
table_cellf(arena, table, "%.*s", ArrayCount(sec->name), sec->name);
|
||||
|
||||
table_default_align(table, TABLE_CellFlag_RightAlign);
|
||||
table_cellf(arena, table, "%$u", sec->vsize);
|
||||
table_cellf(arena, table, "0x%x", sec->voff);
|
||||
table_cellf(arena, table, "%$u", sec->fsize);
|
||||
table_cellf(arena, table, "0x%x", sec->foff);
|
||||
table_default_align(table, TABLE_CellFlag_LeftAlign);
|
||||
|
||||
// memory flags
|
||||
// TODO(allen): here we want to be able to write this cell
|
||||
// by writing into a stream
|
||||
{
|
||||
stream_clear(tempstr);
|
||||
stream_printf(tempstr, (sec->flags & PE_SectionFlag_MEM_READ )?"r":"-");
|
||||
stream_printf(tempstr, (sec->flags & PE_SectionFlag_MEM_WRITE )?"w":"-");
|
||||
stream_printf(tempstr, (sec->flags & PE_SectionFlag_MEM_EXECUTE)?"x":"-");
|
||||
table_cell(arena, table, stream_read(arena, tempstr));
|
||||
}
|
||||
|
||||
table_default_align(table, TABLE_CellFlag_RightAlign);
|
||||
table_cellf(arena, table, "%u", sec->relocation_count);
|
||||
table_cellf(arena, table, "%u", sec->line_number_count);
|
||||
table_default_align(table, TABLE_CellFlag_LeftAlign);
|
||||
}
|
||||
}
|
||||
|
||||
stream_printf(stream, "SECTIONS: (Total %u)\n", section_count);
|
||||
table_print(stream, table, &table_wire_style);
|
||||
stream_printf(stream, "\n");
|
||||
}
|
||||
|
||||
stream_fprint(stdout, stream);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
#ifndef MR4TH_PE_TABLE_H
|
||||
#define MR4TH_PE_TABLE_H
|
||||
|
||||
////////////////////////////////
|
||||
// PE Tabulator Argument Types
|
||||
|
||||
typedef struct PETAB_Args{
|
||||
String8 input_file_name;
|
||||
} PETAB_Args;
|
||||
|
||||
////////////////////////////////
|
||||
// PE Tabulator Argument Functions
|
||||
|
||||
function PETAB_Args* petab_args(Arena *arena, String8List *args);
|
||||
|
||||
////////////////////////////////
|
||||
// Entry Point
|
||||
|
||||
int main(int argc, char **argv);
|
||||
|
||||
#endif //MR4TH_PE_TABLE_H
|
||||
|
|
@ -2,9 +2,80 @@
|
|||
** C Scripting Example #1
|
||||
*/
|
||||
|
||||
#include "base.h"
|
||||
#include "symbol_set.h"
|
||||
|
||||
#include "example1.h"
|
||||
|
||||
#include "base.c"
|
||||
|
||||
COMMAND_SCRIPT(foo, "Generates foo and increments the foo counter"){
|
||||
printf("foo, ");
|
||||
ctx->foo += 1;
|
||||
}
|
||||
|
||||
COMMAND_SCRIPT(bar, "Generates bar and decrements the foo counter"){
|
||||
printf("bar, ");
|
||||
ctx->foo -= 1;
|
||||
}
|
||||
|
||||
COMMAND_SCRIPT(baz,
|
||||
"Generates 2 bars if the foo counter is positive, "
|
||||
"generates 2 foos if the foo counter is negative, "
|
||||
"otherwise generates baz"){
|
||||
if (ctx->foo > 0){
|
||||
printf("bar, bar, ");
|
||||
}
|
||||
else if (ctx->foo < 0){
|
||||
printf("foo, foo, ");
|
||||
}
|
||||
else{
|
||||
printf("baz, ");
|
||||
}
|
||||
}
|
||||
|
||||
int main(void){
|
||||
// init sequence
|
||||
U32 command_ids[] = {
|
||||
COMMAND_ID(foo), COMMAND_ID(foo), COMMAND_ID(baz),
|
||||
COMMAND_ID(bar), COMMAND_ID(baz), COMMAND_ID(bar),
|
||||
COMMAND_ID(foo), COMMAND_ID(bar), COMMAND_ID(baz),
|
||||
};
|
||||
|
||||
// display the legend of rules
|
||||
printf("RULES:\n");
|
||||
{
|
||||
EX1_Command *commands = SymbolBasePtr(EX1_CommandSymbols);
|
||||
U64 count = SymbolCount(EX1_CommandSymbols);
|
||||
for (U64 i = 0; i < count; i += 1){
|
||||
EX1_Command *command = commands + i;
|
||||
printf("%.*s -> %.*s\n",
|
||||
str8_expand(command->name),
|
||||
str8_expand(command->description));
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
// display the sequence
|
||||
printf("SEQUENCE:\n");
|
||||
for (U32 i = 0; i < sizeof(command_ids)/sizeof(command_ids[0]); i += 1){
|
||||
U32 id = command_ids[i];
|
||||
EX1_Command *command = COMMAND_METADATA_FROM_ID(id);
|
||||
printf("%.*s, ", str8_expand(command->name));
|
||||
}
|
||||
printf("\n\n");
|
||||
|
||||
// run the sequence
|
||||
printf("OUTPUT:\n");
|
||||
{
|
||||
EX1_Ctx ctx = {0};
|
||||
for (U32 i = 0; i < sizeof(command_ids)/sizeof(command_ids[0]); i += 1){
|
||||
U32 id = command_ids[i];
|
||||
EX1_Command *command = COMMAND_METADATA_FROM_ID(id);
|
||||
command->hook(&ctx);
|
||||
}
|
||||
}
|
||||
printf("\n\n");
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
|
@ -1,11 +1,33 @@
|
|||
/*
|
||||
** C Scripting Example #1
|
||||
*/
|
||||
#ifndef EXAMPLE1_H
|
||||
#define EXAMPLE1_H
|
||||
|
||||
#ifndef C_SCRIPTING_EXAMPLE1_H
|
||||
#define C_SCRIPTING_EXAMPLE1_H
|
||||
////////////////////////////////
|
||||
// Setup a Symbol Set
|
||||
|
||||
// TODO(allen):
|
||||
typedef struct EX1_Ctx{
|
||||
S64 foo;
|
||||
} EX1_Ctx;
|
||||
|
||||
#endif //C_SCRIPTING_EXAMPLE1_H
|
||||
typedef void EX1_Hook(EX1_Ctx *ctx);
|
||||
|
||||
typedef struct EX1_Command{
|
||||
String8 name;
|
||||
String8 description;
|
||||
EX1_Hook *hook;
|
||||
} EX1_Command;
|
||||
|
||||
#define SYMBOL_SET_DEFINE EX1_CommandSymbols
|
||||
#define EX1_CommandSymbols_Type EX1_Command
|
||||
#define EX1_CommandSymbols_section ".ex1CMD"
|
||||
#include "symbol_set.define.h"
|
||||
|
||||
#define COMMAND_ID(N) SymbolID(EX1_CommandSymbols, N)
|
||||
#define COMMAND_DECL(N) SymbolDeclare(EX1_CommandSymbols, N)
|
||||
#define COMMAND_METADATA_FROM_ID(id) SymbolMetadataFromID(EX1_CommandSymbols, id)
|
||||
|
||||
#define COMMAND_SCRIPT(N,desc) \
|
||||
void cmdhook_##N(EX1_Ctx *ctx); \
|
||||
SymbolDefine(EX1_CommandSymbols, N) = { str8_lit_const(#N), str8_lit_const(desc), cmdhook_##N }; \
|
||||
void cmdhook_##N(EX1_Ctx *ctx)
|
||||
|
||||
#endif //EXAMPLE1_H
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
static U64 SymbolCount(SYMBOL_SET_DEFINE) = 0;
|
||||
static SYMBOL__TYPE(SYMBOL_SET_DEFINE) * SymbolBasePtr(SYMBOL_SET_DEFINE) = 0;
|
||||
static SYMBOL__TYPE(SYMBOL_SET_DEFINE) SYMBOL__SYM(SYMBOL_SET_DEFINE,0);
|
||||
#if COMPILER_CL
|
||||
# pragma SYMBOL__CL_PRAGMA
|
||||
#endif
|
||||
BEFORE_MAIN(){
|
||||
RangePtr image = os_this_image();
|
||||
RangePtr range = selfimg_get_section(image, str8_lit(GLUE(SYMBOL_SET_DEFINE,_section)));
|
||||
SymbolCount(SYMBOL_SET_DEFINE) = (range.opl - range.first)/sizeof(SYMBOL__TYPE(SYMBOL_SET_DEFINE));
|
||||
SymbolBasePtr(SYMBOL_SET_DEFINE) = (SYMBOL__TYPE(SYMBOL_SET_DEFINE)*)(range.first);
|
||||
}
|
||||
#undef SYMBOL_SET_DEFINE
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
** Symbol Set
|
||||
*/
|
||||
|
||||
#ifndef SYMBOL_SET_H
|
||||
#define SYMBOL_SET_H
|
||||
|
||||
////////////////////////////////
|
||||
// Copy-Pastable
|
||||
#if 0
|
||||
|
||||
// To define a Symbol Set
|
||||
#define SYMBOL_SET_DEFINE example_name
|
||||
#define example_name_Type ExampleType
|
||||
#define example_name_section ".exmpl"
|
||||
#include "symbol_set.define.h"
|
||||
|
||||
// Common wrappers to put around a Symbol Set (after defining it)
|
||||
#define EXAMPLE_ID(N) SymbolID(example_name, N)
|
||||
#define EXAMPLE_RAW(N) SymbolRaw(example_name, N)
|
||||
#define EXAMPLE_DECL(N) SymbolDeclare(example_name, N)
|
||||
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
// Symbol Set System
|
||||
|
||||
// Symbol Set key terms:
|
||||
// "count" - the total number of symbols in this set
|
||||
// "baseptr" - the pointer to the base of the array of symbol data
|
||||
// "oplptr" - the pointer to the spot one past the last element of the array
|
||||
// "id" - the 1-based index of the symbol
|
||||
// id=0 stands for the special 'nil' case
|
||||
// id values in the range [1,count] stand for a symbol in the set
|
||||
// "metadata" - a pointer to the slot in the array for this symbol
|
||||
// "raw" - address of the metadata as an integer
|
||||
|
||||
// user interface
|
||||
|
||||
#define SymbolDeclare(E,N) SECTION(E##_section) SYMBOL__TYPE(E) SYMBOL__SYM(E,N)
|
||||
|
||||
#define SymbolDefine(E,N) DO_NOT_ELIMINATE(SYMBOL__SYM(E,N)) SymbolDeclare(E,N)
|
||||
#define SymbolDefineNameless(E) SymbolDefine(E,GLUE(auto,__COUNTER__))
|
||||
|
||||
#define SymbolCount(E) GLUE(E, _count)
|
||||
#define SymbolBasePtr(E) GLUE(E, _baseptr)
|
||||
#define SymbolOplPtr(E) (SymbolBasePtr(E) + SymbolCount(E))
|
||||
|
||||
#define SymbolMetadata(E,N) (&SYMBOL__SYM(E,N))
|
||||
#define SymbolID(E,N) SymbolIDFromMetadata(E, SymbolMetadata(E,N))
|
||||
|
||||
#define SymbolIDFromMetadata(E,ptr) \
|
||||
((SymbolBasePtr(E) <= (ptr) && (ptr) < SymbolOplPtr(E))? \
|
||||
(U32)(1 + ((ptr) - SymbolBasePtr(E))):0)
|
||||
|
||||
#define SymbolMetadataFromID(E,id) \
|
||||
((1 <= (id) && (id) <= SymbolCount(E))?\
|
||||
(SymbolBasePtr(E) + (id) - 1):(&SYMBOL__SYM(E,0)))
|
||||
|
||||
#define SymbolRaw(E,N) IntFromPtr(SymbolMetadata(E,N))
|
||||
#define SymbolIDFromRaw(E,raw) SymbolIDFromMetadata(E,(SYMBOL__TYPE(E)*)(PtrFromInt(raw)))
|
||||
#define SymbolRawFromID(E,id) IntFromPtr(SymbolMetadataFromID(E,id))
|
||||
|
||||
// internal
|
||||
|
||||
#define SYMBOL__TYPE(E) GLUE(E,_Type)
|
||||
#define SYMBOL__SYM(E,N) GLUE(E, GLUE(__, N))
|
||||
|
||||
#define SYMBOL__RAW_BASE(E) IntFromPtr(SymbolBasePtr(E))
|
||||
#define SYMBOL__RAW_OPL(E) (SYMBOL__RAW_BASE(E) + SymbolCount(E)*sizeof(SYMBOL__TYPE(E)))
|
||||
|
||||
#define SYMBOL__BEFORE_MAIN_NAME GLUE(SYMBOL_SET_DEFINE,__init)
|
||||
#define SYMBOL__CL_PRAGMA section(GLUE(SYMBOL_SET_DEFINE,_section),read,write)
|
||||
|
||||
|
||||
#endif //SYMBOL_SET_H
|
||||
|
||||
Loading…
Reference in New Issue