major version 1.0
parent
cc1522760f
commit
e865dc349e
640
README.md
640
README.md
|
|
@ -1,189 +1,553 @@
|
||||||
# C Scripting Introduction
|
# C-Scripting
|
||||||
|
|
||||||
"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.
|
*Allen Webster. June 28 2026*
|
||||||
|
|
||||||
### Introduction: The Code-Data Binding Problem
|
The only way forward is inside out.
|
||||||
|
|
||||||
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.
|
### Index
|
||||||
|
|
||||||
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".
|
1. Start C-Scripting in your C program.
|
||||||
|
2. What is C-Scripting?
|
||||||
|
3. How does it work?
|
||||||
|
4. Known pitfalls and unexplored treachery.
|
||||||
|
5. Introduction to the Symbol Set programming primitives.
|
||||||
|
6. Awesome things you can do with C-Scripting.
|
||||||
|
7. The end.
|
||||||
|
|
||||||
`CLIFlag = (name:String & abbr:String & arg_type:ArgType & desc:String & ???:???)`
|
## 1. Start C-Scripting in your C program.
|
||||||
|
|
||||||
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:
|
0. Pick a project of yours to integrate with - or start an empty "Hello World!" project to play with it.
|
||||||
|
|
||||||
**Immediate Mode CLI**
|
1. Copy the files in the `symbol_set` folder into your project, add that folder to your includes path.
|
||||||
```
|
|
||||||
{
|
2. If you are on Linux compile `symbol_set.ld_meta`. The shell script `build_ld_meta.sh` builds this program with `clang`. You will want to get the compiled version of this file ready at
|
||||||
if (cli_flag(clictx, "fast", "F", ArgType_None, "go as fast as possible")){
|
|
||||||
// do some init path stuff
|
3. In any compilation unit where you are going to be C-Scripting, `#include "symbol_set.h"`.
|
||||||
}
|
|
||||||
if (cli_flag(clictx, "start_time", "S", ArgType_TimeStamp,
|
4. Before the header, `#define SY__MAIN` -- If you have multiple compilation units, `#define SY__MAIN` into just one of them (perhaps `main.c`).
|
||||||
"set the time where the output stream begins (>= 0:00) (default 0:00)")){
|
|
||||||
TimeStamp time_stamp = cli_read_arg_TimeStamp(clictx);
|
At this point your program should build and behave as it did before setup. If something went wrong for you when you tried, you can contact `support@mr4th.com` and I can try to help you. If it does build, then you're ready to start C-Scripting!
|
||||||
// do some init path stuff
|
|
||||||
|
## 2. What is C-Scripting?
|
||||||
|
|
||||||
|
C-Scripting is when you're programming in C, and you've got an underlying architecture that lets you tap into features or expressivity that feel more scripting-like than C-like. I named this particular project "C-Scripting" but the spirit of the name goes back much futher. It's the idea that C doesn't have to be unproductive if you make smart decisions about how you equip yourself with tools.
|
||||||
|
|
||||||
|
By looking for new ways to engage in C-Scripting, I have had two radical transformations to my style of C. The first came from embracing Arenas and non-conflicting local scratchs. This repository contains the kernel of my second radical transformation, a data structure I call a "Symbol Set".
|
||||||
|
|
||||||
|
There are many ways to C-Script, but outside of this little discussion of the spirit of C-Scripting, *this* document is about C-Scripting with Symbol Sets.
|
||||||
|
|
||||||
|
### What is a Symbol Set?
|
||||||
|
|
||||||
|
When you define a symbol set, you give it a name, and a type. Symbol sets live at global scope, and act like an enum and an array working together. The type given in the definition sets the type of the array elements.
|
||||||
|
|
||||||
|
When you define a symbol, you specify which symbol set it belongs to. The symbol is assigned a unique id in the enum and a corresponding slot in the array. When you define a symbol, you define the static initialization for the corresponding slot in the array. Symbols often have names, but there are also great uses for unnamed symbols. Unnamed symbols still get an id and a corresponding slot in the array, they just can't be referenced statically by other code. Usually you do this when you have no reason to use the names and it would be tedious to have to come up with pointless unique names.
|
||||||
|
|
||||||
|
You can imagine it looks sort of like this:
|
||||||
|
```C
|
||||||
|
// define my Command type
|
||||||
|
struct MyCommand{
|
||||||
|
String8 name;
|
||||||
|
String8 description;
|
||||||
|
Hook *hook;
|
||||||
|
};
|
||||||
|
|
||||||
|
// define the MY_COMMAND symbol set
|
||||||
|
SYMBOL_SET_DEFINE(MY_COMMAND, MyCommand);
|
||||||
|
|
||||||
|
// define some commands
|
||||||
|
MY_COMMAND_DEFINE(Foo, "Do Foo."){
|
||||||
|
do_foo(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
MY_COMMAND_DEFINE(EasyBar, "If it's not too hard, do Bar."){
|
||||||
|
if (difficulty(ctx) < 3){
|
||||||
|
do_bar(ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
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.
|
You can then use these symbols essentially as if you had written the non C-Scripted version shown below:
|
||||||
|
|
||||||
**Table Driven CLI**
|
|
||||||
```
|
```
|
||||||
void cli_p_fast(CLICtx *ctx, void *arg){ /*...*/ }
|
void mycommand__Foo(void*){
|
||||||
void cli_p_state_time(CLICtx *ctx, void *arg){ /*...*/ }
|
do_foo(ctx);
|
||||||
|
|
||||||
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 },
|
|
||||||
}
|
}
|
||||||
```
|
void mycommand__EasyBar(void*){
|
||||||
|
if (difficulty(ctx) < 3){
|
||||||
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.
|
do_bar(ctx);
|
||||||
|
}
|
||||||
**Metaprogramming**
|
|
||||||
```
|
|
||||||
CLI_FLAG(fast, "F", ArgType_None, "go as fast as possible"){
|
|
||||||
// ...
|
|
||||||
}
|
}
|
||||||
CLI_FLAG(start_time, "S", ArgType_TimeStamp,
|
enum MY_COMMAND_ID{
|
||||||
"set the time where the output stream begins (>= 0:00) (default 0:00)"){
|
MY_COMMAND_ID__NULL = 0,
|
||||||
// ...
|
MY_COMMAND_ID__Foo,
|
||||||
}
|
MY_COMMAND_ID__EasyBar,
|
||||||
```
|
|
||||||
|
|
||||||
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 AMD64, 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 = {
|
MyCommand MY_COMMAND_array[] = {
|
||||||
"bar", MY_THING_GROUP(FooBarGroup), "Generates a bar and decrements the foo counter", bar_hook
|
{ 0 },
|
||||||
|
{ str8("Foo"), str8("Do Foo."), mycommand__Foo },
|
||||||
|
{ str8("EasyBar"), str8("If it's not too hard, do Bar."), mycommand__EasyBar }
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
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!
|
So you can loop over the array, and statically reference the symbol names to get indices into the array.
|
||||||
|
|
||||||
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.
|
## 3. How does it work?
|
||||||
|
|
||||||
We can achieve this much with a macro like this:
|
### Implementing the Gather: Data Sections
|
||||||
|
|
||||||
|
Under the hood, symbol sets are implemented by assigning each one a special data sections.
|
||||||
|
|
||||||
|
Data sections exist in object files and executable files after you compile your code all the time, but usually we don't think about it. Typically there is a `.text` section that contains the executable code, a `.data` section that contains read-write data with non-zero initialized values, a `.rdata` section or `.rodata` for read only data, and a `.bss` section for read-write data that should be zero initialized, plus a handful of others that can contain information for other things like stack unwinding or debug information.
|
||||||
|
|
||||||
|
Why use data sections for this? Because that's how you get the compiler to gather up all of the global variables in the same set into a single array. C doesn't have a feature that works this way on purpose. But any compiler that supports an extension that lets you assign a global variable to a specific data section, already contains the necessary internal logic to achieve this feature, it just couples that logic to the output data sections. And that's why I use data sections for this.
|
||||||
|
|
||||||
|
### Locating Data Sections
|
||||||
|
|
||||||
|
In order for this to work, we have to be able to find the base pointer of the array, and either the count of symbols, or the pointer to the one-past-last slot in the array.
|
||||||
|
|
||||||
|
#### Linux Version: Linker Scripting
|
||||||
|
|
||||||
|
On Linux the solution I have arranged for this is the program `symbol_set.ld_meta`. The way this program works is it scans your object files before you link them, and it generates a linker script. Then when you link your program with all those object files you also pass the linker script, and it tells the linker how to generate symbols that mark the beginning and end of each section, and as a bonus it packs all the mini data sections down into the normal .data section.
|
||||||
|
|
||||||
|
In order for the `symbol_set.ld_meta` program to know which data sections and symbols need to be arranged, I adopt the restriction that sections that implement symbol sets have to start with `.sy.`. This seems to me to be in keeping with the traditional way of using the name of the section to organize how it interacts with the "tool chain" programs.
|
||||||
|
|
||||||
|
Even deeper under the hood, the `symbol_set.ld_meta` program builds a list of all the sections it sees that start with `.sy.` and also all the unresolved symbols it sees that look like markers for symbol set ranges (`syfirst__` and `syopl__` prefixes). The rest is a matter of generating a linker script like this:
|
||||||
|
`sy.ld`
|
||||||
```
|
```
|
||||||
#if COMPILER_CLANG || COMPILER_GCC
|
SECTIONS {
|
||||||
# define SECTION(N) __attribute__((__section__(N)))
|
.sy : {
|
||||||
#elif COMPILER_CL
|
syfirst__cmd = .; *(.sy.cmd); syopl__cmd = .;
|
||||||
# define SECTION(N) __declspec(allocate(N))
|
}
|
||||||
|
}
|
||||||
|
INSERT AFTER .data;
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Windows Version: Self Imaging
|
||||||
|
|
||||||
|
On Windows the tool chain doesn't have anything as nice as a linker script. Instead we pay a little extra compute price on startup using a technique I call "Self Imaging".
|
||||||
|
|
||||||
|
An "Image" in the context of executable formats and program loading is the "hot" version of the executable file. It's the version of the data that exists in the program's memory space, and on Windows our program's "Image" contains the section headers, and so we can find them at runtime.
|
||||||
|
|
||||||
|
It is the entire contents of `symbol_set.c`, and you don't even have to call it! You just include it, and a "Before Main" function calls it for you. The rest of the details are just parsing the PE/COFF headers.
|
||||||
|
|
||||||
|
### Resolving IDs: Pointer Arithmetic
|
||||||
|
|
||||||
|
What we *want* is if we were to reference a symbol like `MY_COMMAND.Foo` that it would resolve to it's final id in the array. Unfortunately, we would need the linker to know about this and it doesn't. The linker can only patch up references to *addresses* because linkers don't have relocations for patching up indexes unfortunately.
|
||||||
|
|
||||||
|
But that ability to patch up addresses gets us close to what we need. Recall, from C's perspective these "symbols" are just globals or static variables. So for example `MY_COMMAND_Foo` might be how you name the variable that stands for the `Foo` symbol of the `MY_COMMAND` symbol set. And therefore `&MY_COMMAND_Foo` is the address-of that variable. But that means, with the base pointer to the symbol set, we can do pointer arithmetic to get our IDs. Think `(&MY_COMMAND_Foo - MY_COMMAND__base)`.
|
||||||
|
|
||||||
|
Unfortunately this means that static references to these IDs are not the low level constants we would want, they resolve to a subtract between a constant and a global variable.
|
||||||
|
|
||||||
|
## 4. Known pitfalls and unexplored treachery.
|
||||||
|
|
||||||
|
There are a few common ways things can go wrong. The most distressing of which is that you can do everything right and still get a section that isn't the right size to reflect the number of symbols you actually created. There are a couple of ways this can happen that I have smoothed over so far.
|
||||||
|
|
||||||
|
First, sometimes small types or types with small alignments don't get packed the way you'd expect. After all, it's not really a C language array, the standard doesn't say they have to be laid out in any particular way, but I have found I can ensure proper packing by using `SY__ALIGN_AS_LIT` on the declaration, another wrapper for non-standard C. Then I can just round the type size up to a multiple 8 to set the underlying stride for the array. The final interface hides this from you, but it's worth noting the loss of packing efficiency for small type sizes.
|
||||||
|
|
||||||
|
Second, sometimes a bunch of null data will get appended to the end. This is "Incremental Linking". When you are building on Windows you have to pass `-INCREMENTAL:NO` to your linker to prevent this, or if you are using `clang` as a linker you pass `-Xlinker -INCREMENTAL:NO`.
|
||||||
|
|
||||||
|
Symbols are not necessarily packed in the order you think, or at least I wouldn't recommend depending on it if it does. Again we're dealing with non-standard behavior of C, the compiler is free to arrange global variables however it wants, and symbol sets remain perfectly useful without having to depend on order.
|
||||||
|
|
||||||
|
Symbol IDs are not serialization-ready on their own. There is no way in this scheme to ensure a symbol gets the same ID between builds. I have a number of ideas on how this can be addressed, but I haven't begun development on any of them yet, so if you start using symbol sets you're currently on your own for the serialization problem.
|
||||||
|
|
||||||
|
When you reference the ID of a symbol, it is not considered a constant expression, because it's not until after linking that the pointer arithmetic could be resolved. But since the C compiler can't see this, it rejects uses of symbol ID references that occur in statically initialized data. This is too bad, because when symbols can reference other symbols, there are so many more powerful ways to use the system. I have a work around for this limitation in the `Raw` handle space for referencing symbols. See `SY_INIT` in section 5 for more on this.
|
||||||
|
|
||||||
|
On Windows, your section names cannot be more than 8 characters long and I've
|
||||||
|
already said you have to use 4 ".sy.". So you have to carefully allocate your 4
|
||||||
|
character section names when you make a new symbol set.
|
||||||
|
|
||||||
|
On Windows, your sections are not compacted together so each takes up a minimum of 4K and is allocated in 4k pages separately. I have a number of candidates for ways to eliminate this either from all builds or at least from release builds, but I haven't developed any of those ideas yet.
|
||||||
|
|
||||||
|
The usefulness of having symbols in small consecutive IDs is great, but it is constrained to singular compiled binaries (executables,.exe,.so,.dll). For instance, in a plugin system, each plugin would have it's own ID space, and therefore to reference a specific symbol you'd need to start using two-part IDs everywhere. So far I haven't developed anything to explore how this would work out.
|
||||||
|
|
||||||
|
## 5. Introduction to the Symbol Set programming primitives.
|
||||||
|
|
||||||
|
In the file `symbol_set.h` there a couple important sections. The first contains some copy pastable boilerplate. The first contains the boilerplate for setting up a symbol set.
|
||||||
|
|
||||||
|
These first 5 line block define the symbol set itself. For instance if `MY_COMMAND` is the name of my symbol set, and `MyCommand` is the type, the code that instantiates the symbol set could be:
|
||||||
|
```C
|
||||||
|
#define SYMBOL_SET_DEFINE MY_COMMAND
|
||||||
|
#define MY_COMMAND_Type MyCommand
|
||||||
|
#define MY_COMMAND_section ".sy.mcmd"
|
||||||
|
#define MY_COMMAND_marker mcmd
|
||||||
|
#include "symbol_set.define.h"
|
||||||
|
```
|
||||||
|
|
||||||
|
The next few blocks define various patterns of helper macros for defining symbols.
|
||||||
|
|
||||||
|
The first block is how I setup macros for defining data-only symbol types.
|
||||||
|
```C
|
||||||
|
#define ZZZ_DEF(N,...) SyDefine(ZZZ, N) = { ... }
|
||||||
|
```
|
||||||
|
For instance you could use symbol sets to sketch out basic sprite metadata by hand. You could setup the definition helper macro like:
|
||||||
|
```C
|
||||||
|
#define SPRITE_DEFINE(N,file,...) \
|
||||||
|
SyDefine(SPRITES, N) = { str8(file), __VA_ARGS__ }
|
||||||
|
```
|
||||||
|
And then you'd use it like:
|
||||||
|
```C
|
||||||
|
// the
|
||||||
|
SPRITE_DEFINE(Hero, "Hero.png", .x = 8, .y = 16);
|
||||||
|
```
|
||||||
|
|
||||||
|
The next block is how I setup macros for defining symbols with an attached function pointer:
|
||||||
|
```C
|
||||||
|
#define ZZZ_DEF(N,...) \
|
||||||
|
static void funczz##N(void*); \
|
||||||
|
SyDefine(ZZZ, N) = { funczz##N, ... }; \
|
||||||
|
static void funczz##N(void *ptr)
|
||||||
|
```
|
||||||
|
This is the version that all the "commands" example are using:
|
||||||
|
```C
|
||||||
|
#define MY_COMMAND_DEFINE(N,desc) \
|
||||||
|
static void my_command__##N(Ctx*); \
|
||||||
|
SyDefine(ZZZ, N) = { str8(#N), str8(desc), my_command__##N }; \
|
||||||
|
static void my_command__##N(Ctx*)
|
||||||
|
```
|
||||||
|
The macro first declares the underlying C function, fills out the global variable initialization and inclues the C function, and then it sets up the signature of the function again, so that you can follow the macro with `{ ... }` the function block.
|
||||||
|
```C
|
||||||
|
MY_COMMAND_DEFINE(Foo, "Do Foo.){
|
||||||
|
do_foo(ctx);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The next block shows how you can also setup symbols that don't have names.
|
||||||
|
```C
|
||||||
|
#define ZZZ_DEF(...) SyDefineUnnamed(ZZZ) = { ... }
|
||||||
|
```
|
||||||
|
This is useful for cases where you're not really interested in the id space of the symbol set, only the collection of values you want to put together declaratively. This can be useful for creating optional attachments to named symbols, or structures that create relationships between named symbols. For instance, you could say one symbol set defines the set of "tags" you can put on another type of symbol, think `MY_COMMAND_TAG` for `MY_COMMAND`. Then you could use unnamed symbols to set these tags:
|
||||||
|
```C
|
||||||
|
#define MY_COMMAND_ADD_TAG(CMD,TAG) \
|
||||||
|
SyDefineUnnamed(MY_COMMAND_TAG_LINKS) = { \
|
||||||
|
SyRaw(MY_COMMAND, CMD), SyRaw(MY_COMMAND_TAG, TAG) }
|
||||||
|
```
|
||||||
|
And then you would use it like:
|
||||||
|
```C
|
||||||
|
MY_COMMAND_ADD_TAG(Foo,FooBar);
|
||||||
|
MY_COMMAND_ADD_TAG(EasyBar,FooBar);
|
||||||
|
MY_COMMAND_ADD_TAG(EasyBar,Easy);
|
||||||
|
```
|
||||||
|
you can then rearrange this data into a matrix or tags lists, or whatever you need during a simple startup processing phase.
|
||||||
|
|
||||||
|
I don't really know any examples of unnamed symbols that don't rely on referencing a symbol id from another symbol, so I now need to explain how we can make this work.
|
||||||
|
|
||||||
|
### Inter-Symbol References
|
||||||
|
|
||||||
|
First, we can't just store IDs into a symbol the way we'd want, because the data we store into symbols has to be statically resolved, but the IDs aren't resolvable until after linking. What we can do is use a variable address as a constant expression. Even though that the final address of a global variable isn't resolved until link time, the language can count on the linker to fill in the gap with relocations. But relocations werent' built for fixing up IDs.
|
||||||
|
|
||||||
|
Instead what we do is we store the `Raw` for the symbol. The `Raw` is just the address of the global variable typed as a `SY__UAddr` an address widthed unsigned integer. Then we use `SyIDFromRaw` at init time to translate all of the `Raw`s into `ID`s in place (for this reason I put symbols in read-write memory even when I am treating them as strictly read-only after the ID fixup).
|
||||||
|
|
||||||
|
I have developed a helper in `symbol_set.init.h` that I use for managing this. You can include this header after `symbol_set.h`. It sets up a symbol set called `SY_INIT` and each element of this set is a function pointer that describes how to fixup the symbol set.
|
||||||
|
|
||||||
|
Using this helper defining a symbol that references another symbol looks like this:
|
||||||
|
|
||||||
|
```C
|
||||||
|
typedef struct MyThing{
|
||||||
|
SY__UAddr other_thing_id;
|
||||||
|
} MyThing;
|
||||||
|
|
||||||
|
// <define a symbol set MY_THING that uses MyThing type>
|
||||||
|
|
||||||
|
#define MY_THING_DEF(N,O) \
|
||||||
|
SyDefine(MY_THING, N) = { SyRaw(OTHER_THING, O) }
|
||||||
|
|
||||||
|
#if SY__MAIN
|
||||||
|
SY_INIT_DEF(MY_THING){
|
||||||
|
for (SyEach(MY_THING, thing)){
|
||||||
|
thing->other_thing_id = SyIDFromRaw(OTHER_THING, thing->other_thing_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
```
|
```
|
||||||
|
|
||||||
In the CL compiler you also need to insist that the data section exists by dropping this somewhere:
|
In summary, I wrap the reference to a symbol in the helper macro to make all the symbol definitions easy on the eyes, and to ensure there that `SyRaw` is used and not `SyID`, then if this is the `SY__MAIN` unit, I define a special `SY_INIT` symbol that describes how to loop over the symbol and fixup `SyRaw`s into `SyID`s. I have to manually make sure the symbol set that I use in `SyRaw` matches the one I use in `SyIDFromRaw` or I will just get 0 ids.
|
||||||
```
|
|
||||||
#pragma section(<section>,read,write)
|
Then I just have to call `sy__run_init();` early in `main`. I don't use a run-before-main for this, because I already use run-before-mains to automate the location of the array on Windows, and you can't do fixup before you locate symbols. `SY_INIT` is like run-before-main except you decide when to run all the `SY_INIT` functions explicitly, and therefore it can be timed strictly after the initial wiring up.
|
||||||
|
|
||||||
|
This way of organizing the fixups feels makes the maintenance of lots of interconnected symbol sets a lot more manageable than it would be otherwise. I just consider the the ID fixup boilerplate a necessary component of defining the symbol set itself, and whenever I modify the symbol set types I try to be sure to recheck the ID fixup at the same time.
|
||||||
|
|
||||||
|
### Symbol Set Referencing Primitives
|
||||||
|
|
||||||
|
After defining a `SYMBOL_SET` here are the primitives you can use that reference it.
|
||||||
|
|
||||||
|
`SyType(SYMBOL_SET)` - Expands to the underlying type of the symbol set.
|
||||||
|
|
||||||
|
`SyDeclare(SYMBOL_SET,N)` - Forward declares the symbol N. Like any other C forward declare you may do this as many times as you want for the same name, so long as you only define it once. This is useful when you want to reference a symbol before you've defined it.
|
||||||
|
|
||||||
|
`SyDefine(SYMBOL_SET,N)` - Sets up the definition of the symbol N. The macro sets up the variable for the symbol, with the type from the `SYMBOL_SET`, and leaves the value unset, you finish the definition by writing ` = { ... };` after the macro.
|
||||||
|
|
||||||
|
`SyDefineUnnamed(SYMBOL_SET)` - Works like `SyDefine` except you don't specify a name.
|
||||||
|
|
||||||
|
`SyAddress(SYMBOL_SET,N)` - Gives the address of the symbol's slot in the set's array, typed as a pointer to the set's underlying type. Static resolution.
|
||||||
|
|
||||||
|
`SyID(SYMBOL_SET,N)` - Gives the 1-based ID of symbol. Literally runtime resolution, theoretically more like link-time resolution.
|
||||||
|
|
||||||
|
`SyRaw(SYMBOL_SET,N)` - Gives the address of the symbol typed as `SY__UAddr`.
|
||||||
|
|
||||||
|
`SyFirst(SYMBOL_SET)` `SyOpl(SYMBOL_SET)` - Gives the address of the first and one-past-last slot of the symbol set's array.
|
||||||
|
|
||||||
|
`SyStride(SYMBOL_SET)` - The stride between elements in the symbol set's array.
|
||||||
|
|
||||||
|
`SyCount(SYMBOL_SET)` - The number of symbols in the symbol set.
|
||||||
|
|
||||||
|
`SyNext(SYMBOL_SET,addr)` - Increments a pointer in the symbol set's array to the next element in the array (basically pointer arithmetic by the `SyStride`).
|
||||||
|
|
||||||
|
`SyEach(SYMBOL_SET,var)` - Expands to the control phrases of a for loop: `for (SyEach(SYMBOL_SET,var)){ ... }`. `var` is a pointer to the set's underlying type, that iterates the whole array.
|
||||||
|
|
||||||
|
`SyEachID(SYMBOL_SET,id)` - Expands to the control phrases of a for loop: `for (SyEachID(SYMBOL_SET,id)){ ... }`. `id` is a `U32` 1-based index that iterates the ids of the symbol set.
|
||||||
|
|
||||||
|
`SyIDFromAddress(SYMBOL_SET,addr)` - Convert a pointer to a symbol to it's ID.
|
||||||
|
|
||||||
|
`SyAddressFromID(SYMBOL_SET,addr)` - Convert an ID to a symbol pointer.
|
||||||
|
|
||||||
|
`SyAddressCheck(SYMBOL_SET,addr)` - Evaluates true if the address is inside the range of the symbol set's array.
|
||||||
|
|
||||||
|
`SyIDCheck(SYMBOL_SET,id)` - Evaluates true if the ID is one of the symbol IDs in the symbol set.
|
||||||
|
|
||||||
|
`SyIDFromAddress_Unchecked` and `SyAddressFromID_Unchecked` - Like `SyIDFromAddress` and `SyAddressFromID`, but skips run-time checking the parameter is in a valid range, only use if you know you've got a valid address/ID.
|
||||||
|
|
||||||
|
`SyIDFromRaw` and `SyIDFromRaw_Unchecked` same as `SyIDFromAddress`/`_Unchecked` except excepts `SY__UAddr` type instead of expecting pointer types.
|
||||||
|
|
||||||
|
`SyFlag(SYMBOL_SET,N)` - Just think `(1 << SyID(SYMBOL_SET,N))`
|
||||||
|
|
||||||
|
## 6. Awesome things you can do with C-Scripting.
|
||||||
|
|
||||||
|
### Organized Command Systems
|
||||||
|
|
||||||
|
Suppose you're building some kind of editor application where you have to organize a lot of editing commands into key bindings, and menus. Further imagine it could look like this:
|
||||||
|
```C
|
||||||
|
EDITOR_COMMAND(InsertTodo, "Insert a TODO comment."){
|
||||||
|
U32 view_id = ed_current_view(ctx);
|
||||||
|
U32 buffer_id = ed_buffer_from_view(ctx, view_id);
|
||||||
|
U32 cursor_pos = ed_cursor_pos_from_view(ctx, view_id);
|
||||||
|
ed_insert(ctx, buffer_id, cursor_pos, str8("// TODO: "));
|
||||||
|
}
|
||||||
|
EDITOR_COMMAND_FLAGS(InsertTodo, ED_CmdFlag_Write);
|
||||||
|
BIND_KEY(DefaultMap, ED_Key_T, ED_Mdfr_Alt, InsertTodo);
|
||||||
```
|
```
|
||||||
|
|
||||||
**Accessing the Data**
|
With a setup like this you could automatically assemble a statically defined keymap. And you could loop over all the commands you've written in your program, check their flags, string search and display their descriptions, and of course execute the command function if you have the parameters it needs.
|
||||||
|
|
||||||
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:
|
### Organized Command Line Parameters
|
||||||
|
|
||||||
1. Locate the module's binary image - this involves a conversation with the operating system.
|
Similarly you could use C-scripting to arrange your command line parsing. Imagine:
|
||||||
2. Parse the image to find the data section - this involves knowledge of the binary file format.
|
```C
|
||||||
|
CMDLN_FLAG("start", "Specify the start time index for the scan. (default 0)",
|
||||||
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);`
|
.duplicate = CMDLN_Behavior_Warning){
|
||||||
|
out->start = cmdln_read_u32(ctx);
|
||||||
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.
|
}
|
||||||
|
CMDLN_FLAG("end", "Specify the end time index for the scan. (default end-of-timeline)",
|
||||||
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.
|
.duplicate = CMDLN_Behavior_Warning){
|
||||||
|
out->end = cmdln_read_u32(ctx);
|
||||||
```
|
}
|
||||||
{
|
CMDLN_FLAG("save", "Specify one or more intermediates to save.",
|
||||||
RangePtr range = selfimg_get_section(str8_lit(".mything"));
|
.duplicate = CMDLN_Behavior_Concatenate){
|
||||||
MyThing *my_thing = (MyThing*)range.first;
|
U32 count = rpg_read_count(ctx);
|
||||||
U64 my_thing_count = ((MyThing*)range.first - (MyThing*)range.opl);
|
for (U32 i = 0; i < count; i += 1){
|
||||||
|
String8 intermediate_name = cmdln_read_idx_str8(ctx, i);
|
||||||
|
U32 intermediate = timeline_intermediate_from_name(intermediate_name);
|
||||||
|
if (intermediate != 0){
|
||||||
|
timeline_add_save(out, intermediate);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Wrapper Macro With Fused Hook Syntax**
|
### State Machine
|
||||||
|
|
||||||
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:
|
You can set up a state machine programming system in a symbol set that looks like this:
|
||||||
|
|
||||||
```
|
```C
|
||||||
#define MY_THING_DEF(name,group,desc,hook) \
|
typedef struct Ctx{
|
||||||
SECTION(".mything") MyThing name = { #name, MY_THING_GROUP(group), #desc, hook }
|
U32 state_id;
|
||||||
|
} 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);
|
|
||||||
```
|
|
||||||
|
|
||||||
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.
|
STATE(GameSetup){
|
||||||
|
game_setup(ctx);
|
||||||
|
state_next(ctx, SyID(STATE, GameScene1));
|
||||||
|
}
|
||||||
|
|
||||||
```
|
STATE(GameScene1){
|
||||||
#define MY_THING_DEF(name,group,desc,hook) \
|
scene_character(ctx, 1, Left, SyID(CHARACTER, Hero));
|
||||||
void hook(MyThingCtx *ctx); \
|
scene_character(ctx, 2, Right, SyID(CHARACTER, DreamShadow));
|
||||||
SECTION(".mything") MyThing name = { #name, MY_THING_GROUP(group), #desc, hook }; \
|
scene_sound_effect(ctx, SyID(SOUND_EFFECT, Eerie));
|
||||||
void hook(MyThingCtx *ctx)
|
scene_line(ctx, 1, "Huh? Is there someone there?");
|
||||||
|
|
||||||
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){
|
|
||||||
// ...
|
// ...
|
||||||
|
scene_line(ctx, 2, "Will you follow me into the deep?");
|
||||||
|
scene_offer_decision(ctx, 1, "Yes", 2, "No");
|
||||||
|
U32 decision = scene_player_decision(ctx);
|
||||||
|
switch (decision){
|
||||||
|
case 1: {
|
||||||
|
state_next(ctx, SyID(STATE, GameScene2Deep));
|
||||||
|
}break;
|
||||||
|
case 2: {
|
||||||
|
state_next(ctx, SyID(STATE, GameScene2Awake));
|
||||||
|
}break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
And I like to take advantage of preprocessor pasting to free myself from the chore of naming the hook:
|
You can grab the symbol name in a macro with `#N` so we can save the symbol names as string data on symbols any time we'd like to, which means we can easily create an interface for running the state machine one step at a time and displaying the state, or logging each state as the machine runs, but a flat state machine is pretty limiting, so I recommend some upgrades.
|
||||||
|
|
||||||
```
|
### Stack Machine
|
||||||
#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"){
|
You can extend the state machine with a stack. When you do a state transition, you can also push a new state onto the stack. Alternatively you can pop the stack.
|
||||||
// ...
|
|
||||||
|
```C
|
||||||
|
typedef struct Ctx{
|
||||||
|
U32 stack[100];
|
||||||
|
U32 stack_count;
|
||||||
|
} Ctx;
|
||||||
|
|
||||||
|
///////////////////////////
|
||||||
|
|
||||||
|
STATE(GameFight){
|
||||||
|
if (fight_exit_condition(ctx)){
|
||||||
|
state_pop(ctx);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
fight_step(ctx);
|
||||||
|
state_stationary(ctx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MY_THING_DEF(bar, FooBarGroup, "Generates a bar and decrements the foo counter"){
|
STATE(GameSceneTutorialBoss){
|
||||||
// ...
|
setup_tutorial_boss(ctx);
|
||||||
|
state_next_push(ctx, SyID(STATE, GameSceneTutorialFinished),
|
||||||
|
SyID(STATE, GameFight);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Reusable C Scripting System**
|
When you push a state, you also set a next state so that when you pop you don't necessarily have to go back to the state that did the push. This way state machines can be called like a subroutine.
|
||||||
|
|
||||||
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:
|
Now when you're logging what happens you could just show the top of the stack, which gives the same effect as stepping line by line in a debugger, but at the granularity of states. You can also "backtrace" this stack and see everything that has led up to the current state, because again it's so easy to connect readable names to these states and automatically print them out.
|
||||||
|
|
||||||
https://git.mr4th.com/mr4th-members/mr4th/src/branch/main/src/mr4th_symbol_set.h
|
So this above code says taht `GamesTutorialBoss` is a state that does some setup, and then it will appear to transition to `GameFight` but it does this by pushing `GameFight`, and at the same time, it sets `GameSceneTutorialFinished` as the next. This way `GameFight` can just pop and is generic and reusable for all sorts of contexts in the state machine, and doesn't need to hardwire itself for this particular relationship to `GameSceneTutorialFinished`.
|
||||||
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!
|
### Stack Frames
|
||||||
|
|
||||||
*-- Allen Webster. April 17th, 2025*
|
You can extend the state machine stack with typed frames that group states together and grant them access to shared variables. When you set the next state, the new state be a member of the same frame as the current state. But when you push a state, you may push any state, and you initialize the new frame that you push.
|
||||||
|
|
||||||
|
```C
|
||||||
|
typedef struct StackNode{
|
||||||
|
struct StackNode *next;
|
||||||
|
void *data;
|
||||||
|
U32 state_id;
|
||||||
|
U32 pop_to;
|
||||||
|
} StackNode;
|
||||||
|
|
||||||
|
typedef struct Ctx{
|
||||||
|
Arena *stack_arena;
|
||||||
|
StackNode *stack;
|
||||||
|
U32 stack_count;
|
||||||
|
} Ctx;
|
||||||
|
|
||||||
|
///////////////////////////
|
||||||
|
|
||||||
|
STACK_FRAME_STRUCT(Fight){
|
||||||
|
CharVars entities[100];
|
||||||
|
U32 entity_count;
|
||||||
|
U32 player_id;
|
||||||
|
F32 quick_time_cooldown;
|
||||||
|
U32 quick_time_entity;
|
||||||
|
};
|
||||||
|
|
||||||
|
STATE(FightStep, Fight){
|
||||||
|
B32 done = 0;
|
||||||
|
U32 quick_times[100];
|
||||||
|
U32 quick_time_entities[100];
|
||||||
|
U32 quick_time_count = 0;
|
||||||
|
// ... gather above variables from frame->entities ...
|
||||||
|
|
||||||
|
if (done){
|
||||||
|
state_pop(ctx);
|
||||||
|
}
|
||||||
|
else if (quick_time_count > 0 && frame->quick_time_cooldown == 0){
|
||||||
|
U32 idx = rng_n(&ctx->rng, quick_time_count);
|
||||||
|
frame->quick_time_cooldown = 5.f;
|
||||||
|
frame->quick_time_entity = quick_time_entities[idx];
|
||||||
|
state_next(ctx, quick_times[idx]);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
frame->quick_time_cooldown = ClampBot(0.f, frame->quick_time_cooldown - ctx->dt);
|
||||||
|
main_update(ctx, frame);
|
||||||
|
state_stationary(ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
STATE(QuickTimeZombieAttack, Fight){
|
||||||
|
qtime_before(ctx, 3.f);
|
||||||
|
qtime_press(ctx, Button_Left);
|
||||||
|
qtime_press(ctx, Button_Right);
|
||||||
|
qtime_press(ctx, Button_Left);
|
||||||
|
if (qtime_success(ctx)){
|
||||||
|
stun_chr(ctx, frame, frame->quick_time_entity);
|
||||||
|
state_next(ctx, SyID(STATE, FightStep));
|
||||||
|
}
|
||||||
|
else if (qtime_fail(ctx)){
|
||||||
|
hit_chr(ctx, frame, frame->player_id, 10);
|
||||||
|
state_next(ctx, SyID(STATE, FightStep));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Because you end up writing your own very simple main loop to run this state machine, and you implement the `state_*` transition functions, you can do things like track how long a state has run for, and make that information available to any of the state scripts `state_timer(ctx)`
|
||||||
|
|
||||||
|
If you want you could then go further and attach other interesting things to the frames in this system, like self logging:
|
||||||
|
```C
|
||||||
|
STACK_FRAME_LOG(Fight){
|
||||||
|
printf("entity_count = %u\n", frame->entity_count);
|
||||||
|
printf("player = [%u] %E\n", frame->player_id, frame->entities + frame->player_id);
|
||||||
|
printf("quick_time_cooldown = %f\n", frame->quick_time_cooldown);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Organized Help Information
|
||||||
|
|
||||||
|
Suppose you've got a lot of different kinds of symbols, perhaps you've got edit commands, signal filtering functions, file formats, etc. all modeled as symbol sets. Then say you decide that you'd like to start attaching more detailed help information to the symbols whose functioning is especially confusing. You can consider the following trick:
|
||||||
|
|
||||||
|
```C
|
||||||
|
#define RuleClassXList(X) \
|
||||||
|
X(COMMAND) \
|
||||||
|
X(SIGNAL_FILER) \
|
||||||
|
X(FILE_FORMAT)
|
||||||
|
|
||||||
|
typedef enum RuleClass{
|
||||||
|
RuleClass_NULL = 0,
|
||||||
|
#define X(RC) RuleClass_##RC,
|
||||||
|
RuleClassXList(X)
|
||||||
|
#undef X
|
||||||
|
RuleClass_COUNT
|
||||||
|
} RuleClass;
|
||||||
|
|
||||||
|
typedef struct Rule{
|
||||||
|
RuleClass rc;
|
||||||
|
UAddr id;
|
||||||
|
String8 text;
|
||||||
|
} Rule;
|
||||||
|
|
||||||
|
// <setup a rules symbol set>
|
||||||
|
|
||||||
|
#define RULE(RC,N,text) SyDefine(RC,N) = { .rc = RuleClass_##RC, .id = SyRaw(RC,N), .text = str8(text) }
|
||||||
|
|
||||||
|
#if SY__MAIN
|
||||||
|
SY_INIT(RULE){
|
||||||
|
for (SyEach(RULE,rule)){
|
||||||
|
switch (rule->rc){
|
||||||
|
#define X(RC) case RuleClass_##RC: rule->id = SyIDFromRaw(RC, rule->id); break;
|
||||||
|
RuleClassXList(X)
|
||||||
|
#undef X
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
```
|
||||||
|
|
||||||
|
With this setup, you can start attaching "rules text" to any named symbol so long as you add that symbol's symbol set to the list of rule classes.
|
||||||
|
|
||||||
|
## 7. The end.
|
||||||
|
|
||||||
|
This is only the beginning.
|
||||||
|
|
||||||
|
There's a final interpretation of the name C-Scripting that I chose for this project. It's also a reference to "C With Classes" the predecessor to C++. In a similar way C-Scripting is an exploratory project shaping something new out of the raw materials of C. But where I want to go next with this is not a programming language.
|
||||||
|
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
@echo off
|
|
||||||
|
|
||||||
set opts=-FC -GR- -EHa- -nologo -Zi -std:c11 -wd5105
|
|
||||||
set code=%cd%
|
|
||||||
pushd build
|
|
||||||
cl %opts% %code%\src\example1.c -Feexample1 -link -INCREMENTAL:NO
|
|
||||||
popd
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
code=$PWD
|
||||||
|
opts=-g
|
||||||
|
inc="-I$code/symbol_set"
|
||||||
|
|
||||||
|
mkdir -p build
|
||||||
|
cd build
|
||||||
|
|
||||||
|
clang -c $code/examples/example1.c $opts $inc
|
||||||
|
./symbol_set.ld_meta example1.o
|
||||||
|
clang -o example1 $code/examples/example1.c $opts $inc -T sy.ld
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
code=$PWD
|
||||||
|
opts=-Wno-switch
|
||||||
|
inc="-I$code/ld_meta/mr4th"
|
||||||
|
|
||||||
|
mkdir -p build
|
||||||
|
cd build
|
||||||
|
|
||||||
|
clang -o symbol_set.ld_meta "$code/ld_meta/symbol_set.ld_meta.c" $opts $inc
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
@echo off
|
||||||
|
|
||||||
|
set code=%cd%
|
||||||
|
set opts=-FC -GR- -EHa- -nologo -Zi -std:c11 -wd5105
|
||||||
|
set inc=-I%code%\symbol_set
|
||||||
|
pushd build
|
||||||
|
cl -Feexample1 %code%\examples\example1.c %opts% %inc% -link -INCREMENTAL:NO
|
||||||
|
popd
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
@echo off
|
||||||
|
|
||||||
|
set code=%cd%
|
||||||
|
set opts=-g
|
||||||
|
set inc=-I%code%\symbol_set
|
||||||
|
pushd build
|
||||||
|
clang -o example1 %code%\examples\example1.c %opts% %inc% -Xlinker -INCREMENTAL:NO
|
||||||
|
popd
|
||||||
|
|
@ -2,12 +2,11 @@
|
||||||
** C Scripting Example #1
|
** C Scripting Example #1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "base.h"
|
#define SY__MAIN 1
|
||||||
#include "symbol_set.h"
|
#include "symbol_set.h"
|
||||||
|
|
||||||
#include "example1.h"
|
#include "example1.h"
|
||||||
|
#include <stdio.h>
|
||||||
#include "base.c"
|
|
||||||
|
|
||||||
COMMAND_SCRIPT(foo, "Generates foo and increments the foo counter"){
|
COMMAND_SCRIPT(foo, "Generates foo and increments the foo counter"){
|
||||||
printf("foo, ");
|
printf("foo, ");
|
||||||
|
|
@ -37,22 +36,17 @@ COMMAND_SCRIPT(baz,
|
||||||
int main(void){
|
int main(void){
|
||||||
// init sequence
|
// init sequence
|
||||||
U32 command_ids[] = {
|
U32 command_ids[] = {
|
||||||
COMMAND_ID(foo), COMMAND_ID(foo), COMMAND_ID(baz),
|
SyID(EX1_COMMAND, foo), SyID(EX1_COMMAND, foo), SyID(EX1_COMMAND, baz),
|
||||||
COMMAND_ID(bar), COMMAND_ID(baz), COMMAND_ID(bar),
|
SyID(EX1_COMMAND, bar), SyID(EX1_COMMAND, baz), SyID(EX1_COMMAND, bar),
|
||||||
COMMAND_ID(foo), COMMAND_ID(bar), COMMAND_ID(baz),
|
SyID(EX1_COMMAND, foo), SyID(EX1_COMMAND, bar), SyID(EX1_COMMAND, baz),
|
||||||
};
|
};
|
||||||
|
|
||||||
// display the legend of rules
|
// display the legend of rules
|
||||||
printf("RULES:\n");
|
printf("RULES:\n");
|
||||||
{
|
for (SyEach(EX1_COMMAND, command)){
|
||||||
EX1_Command *commands = SymbolBasePtr(EX1_CommandSymbols);
|
printf("%.*s -> %.*s\n",
|
||||||
U64 count = SymbolCount(EX1_CommandSymbols);
|
(int)(command->name.size), command->name.str,
|
||||||
for (U64 i = 0; i < count; i += 1){
|
(int)(command->description.size), command->description.str);
|
||||||
EX1_Command *command = commands + i;
|
|
||||||
printf("%.*s -> %.*s\n",
|
|
||||||
str8_expand(command->name),
|
|
||||||
str8_expand(command->description));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
|
|
@ -60,8 +54,9 @@ int main(void){
|
||||||
printf("SEQUENCE:\n");
|
printf("SEQUENCE:\n");
|
||||||
for (U32 i = 0; i < sizeof(command_ids)/sizeof(command_ids[0]); i += 1){
|
for (U32 i = 0; i < sizeof(command_ids)/sizeof(command_ids[0]); i += 1){
|
||||||
U32 id = command_ids[i];
|
U32 id = command_ids[i];
|
||||||
EX1_Command *command = COMMAND_METADATA_FROM_ID(id);
|
EX1_Command *command = SyAddressFromID(EX1_COMMAND, id);
|
||||||
printf("%.*s, ", str8_expand(command->name));
|
printf("%.*s, ",
|
||||||
|
(int)(command->name.size), command->name.str);
|
||||||
}
|
}
|
||||||
printf("\n\n");
|
printf("\n\n");
|
||||||
|
|
||||||
|
|
@ -71,7 +66,7 @@ int main(void){
|
||||||
EX1_Ctx ctx = {0};
|
EX1_Ctx ctx = {0};
|
||||||
for (U32 i = 0; i < sizeof(command_ids)/sizeof(command_ids[0]); i += 1){
|
for (U32 i = 0; i < sizeof(command_ids)/sizeof(command_ids[0]); i += 1){
|
||||||
U32 id = command_ids[i];
|
U32 id = command_ids[i];
|
||||||
EX1_Command *command = COMMAND_METADATA_FROM_ID(id);
|
EX1_Command *command = SyAddressFromID(EX1_COMMAND, id);
|
||||||
command->hook(&ctx);
|
command->hook(&ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
#ifndef EXAMPLE1_H
|
||||||
|
#define EXAMPLE1_H
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// Example 1 Header
|
||||||
|
|
||||||
|
#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 String8{
|
||||||
|
U8 *str;
|
||||||
|
U64 size;
|
||||||
|
} String8;
|
||||||
|
|
||||||
|
typedef struct EX1_Ctx{
|
||||||
|
S64 foo;
|
||||||
|
} EX1_Ctx;
|
||||||
|
|
||||||
|
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_COMMAND
|
||||||
|
#define EX1_COMMAND_Type EX1_Command
|
||||||
|
#define EX1_COMMAND_section ".sy.cmd"
|
||||||
|
#define EX1_COMMAND_marker cmd
|
||||||
|
#include "symbol_set.define.h"
|
||||||
|
|
||||||
|
#define COMMAND_SCRIPT(N,desc) \
|
||||||
|
void ex1_command__##N(EX1_Ctx *ctx); \
|
||||||
|
SyDefine(EX1_COMMAND, N) = { \
|
||||||
|
.name = {(U8*)#N, sizeof(#N) - 1}, \
|
||||||
|
.description = {(U8*)desc, sizeof(desc) - 1}, \
|
||||||
|
.hook = ex1_command__##N }; \
|
||||||
|
void ex1_command__##N(EX1_Ctx *ctx)
|
||||||
|
|
||||||
|
#endif //EXAMPLE1_H
|
||||||
|
|
@ -1,38 +1,33 @@
|
||||||
version(2);
|
version(2);
|
||||||
project_name = "example1";
|
project_name = "example1";
|
||||||
patterns = {
|
patterns = {
|
||||||
"*.c",
|
"*.c", "*.cpp", "*.h", "*.m", "*.bat", "*.sh", "*.4coder", "*.txt"
|
||||||
"*.cpp",
|
|
||||||
"*.h",
|
|
||||||
"*.m",
|
|
||||||
"*.bat",
|
|
||||||
"*.sh",
|
|
||||||
"*.4coder",
|
|
||||||
"*.txt",
|
|
||||||
};
|
|
||||||
blacklist_patterns = {
|
|
||||||
".*",
|
|
||||||
};
|
|
||||||
load_paths_base = {
|
|
||||||
{ ".", .relative = true, .recursive = true, },
|
|
||||||
};
|
};
|
||||||
|
blacklist_patterns = { ".*" };
|
||||||
|
load_paths_base = { { ".", .relative = true, .recursive = true } };
|
||||||
load_paths = {
|
load_paths = {
|
||||||
.win = load_paths_base,
|
.win = load_paths_base, .linux = load_paths_base, .mac = load_paths_base
|
||||||
.linux = load_paths_base,
|
|
||||||
.mac = load_paths_base,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
commands = {
|
commands = {
|
||||||
.build = { .out = "*compilation*", .footer_panel = true, .save_dirty_files = true,
|
.build_with_clang = { .out = "*compilation*",
|
||||||
.win = "build.bat",
|
.footer_panel = true, .save_dirty_files = true,
|
||||||
.linux = "./build.sh",
|
.win = "build_with_clang.bat", .linux = "./build.sh", .mac = "./build.sh"
|
||||||
.mac = "./build.sh", },
|
},
|
||||||
|
.build_with_cl = { .out = "*compilation*",
|
||||||
|
.footer_panel = true, .save_dirty_files = true,
|
||||||
|
.win = "build_with_cl.bat"
|
||||||
|
},
|
||||||
|
.build_ld_meta = { .out = "*compilation*",
|
||||||
|
.footer_panel = true, .save_dirty_files = true,
|
||||||
|
.linux = "./build_ld_meta.sh", .mac = "./build_ld_meta.sh"
|
||||||
|
},
|
||||||
.run = { .out = "*run*", .footer_panel = false, .save_dirty_files = false,
|
.run = { .out = "*run*", .footer_panel = false, .save_dirty_files = false,
|
||||||
.win = "build\\example1",
|
.win = "build\\example1", .linux = "build/example1", .mac = "build/example1"
|
||||||
.linux = "build/example1",
|
},
|
||||||
.mac = "build/example1", },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
fkey_command = {
|
fkey_command = {
|
||||||
.F1 = "build",
|
.F1 = "build_with_cl",
|
||||||
.F2 = "run",
|
.F2 = "run",
|
||||||
};
|
};
|
||||||
|
|
|
||||||
62
src/base.c
62
src/base.c
|
|
@ -1,62 +0,0 @@
|
||||||
////////////////////////////////
|
|
||||||
// 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
|
|
||||||
|
|
||||||
// see: https://devblogs.microsoft.com/oldnewthing/20041025-00/?p=37483
|
|
||||||
static void*
|
|
||||||
os_this_image(void){
|
|
||||||
extern U8 __ImageBase[];
|
|
||||||
void *result = __ImageBase;
|
|
||||||
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.img_get_section.c"
|
|
||||||
|
|
||||||
static RangePtr
|
|
||||||
self_img_get_section(void *image, String8 name){
|
|
||||||
RangePtr result = pe_img_get_section(image, name);
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
# error selfimg_get_section not implemented for this OS
|
|
||||||
#endif
|
|
||||||
252
src/base.h
252
src/base.h
|
|
@ -1,252 +0,0 @@
|
||||||
////////////////////////////////
|
|
||||||
// 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 void* os_this_image(void);
|
|
||||||
|
|
||||||
static RangePtr self_img_get_section(void *image, String8 name);
|
|
||||||
|
|
@ -1,518 +0,0 @@
|
||||||
////////////////////////////////
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
@ -1,567 +0,0 @@
|
||||||
/*
|
|
||||||
** 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);
|
|
||||||
}
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
#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
|
|
||||||
|
|
@ -1,831 +0,0 @@
|
||||||
#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
|
|
||||||
|
|
@ -1,68 +0,0 @@
|
||||||
////////////////////////////////
|
|
||||||
// PE Get Section Function
|
|
||||||
|
|
||||||
static RangePtr
|
|
||||||
pe_img_get_section(void *image_raw, String8 name){
|
|
||||||
U8 *image = (U8*)image_raw;
|
|
||||||
|
|
||||||
// dos header
|
|
||||||
PE_DosHeader *dos_header = (PE_DosHeader*)(image);
|
|
||||||
if (dos_header->magic != PE_MSDOS_MAGIC){
|
|
||||||
dos_header = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// coff header
|
|
||||||
PE_CoffHeader *coff_header = 0;
|
|
||||||
U64 after_coff_header_offset = 0;
|
|
||||||
if (dos_header != 0){
|
|
||||||
U64 pe_signature_offset = dos_header->coff_file_offset;
|
|
||||||
U64 coff_header_offset = pe_signature_offset + sizeof(U32);
|
|
||||||
U32 pe_signature = *(U32*)(image + pe_signature_offset);
|
|
||||||
if (pe_signature == PE_SIGNATURE){
|
|
||||||
coff_header = (PE_CoffHeader*)(image + coff_header_offset);
|
|
||||||
after_coff_header_offset = coff_header_offset + sizeof(*coff_header);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// section table offset & count
|
|
||||||
U32 section_table_offset = 0;
|
|
||||||
U32 section_count = 0;
|
|
||||||
if (coff_header != 0){
|
|
||||||
section_table_offset = ( after_coff_header_offset
|
|
||||||
+ coff_header->optional_header_size);
|
|
||||||
section_count = coff_header->section_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
// scan section table
|
|
||||||
PE_SectionHeader *match = 0;
|
|
||||||
{
|
|
||||||
PE_SectionHeader *sec = (PE_SectionHeader*)(image + section_table_offset);
|
|
||||||
for (U32 i = 0; i < section_count; i += 1, sec += 1){
|
|
||||||
U8 *secptr = sec->name;
|
|
||||||
U8 *secopl = sec->name + sizeof(sec->name);
|
|
||||||
U8 *keyptr = name.str;
|
|
||||||
U8 *keyopl = name.str + name.size;
|
|
||||||
B32 string_match = 1;
|
|
||||||
for (;*secptr != 0 && secptr < secopl && keyptr < keyopl;
|
|
||||||
secptr += 1, keyptr += 1){
|
|
||||||
if (*secptr != *keyptr){
|
|
||||||
string_match = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (string_match){
|
|
||||||
match = sec;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// fill result
|
|
||||||
RangePtr result = {0};
|
|
||||||
if (match != 0){
|
|
||||||
result.first = image + match->voff;
|
|
||||||
result.opl = result.first + match->vsize;
|
|
||||||
}
|
|
||||||
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
#ifndef MR4TH_PE_IMG_GET_SECTION_H
|
|
||||||
#define MR4TH_PE_IMG_GET_SECTION_H
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
// PE Get Section Function
|
|
||||||
|
|
||||||
static RangePtr pe_img_get_section(void *image, String8 name);
|
|
||||||
|
|
||||||
#endif //MR4TH_PE_IMG_GET_SECTION_H
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
#ifndef EXAMPLE1_H
|
|
||||||
#define EXAMPLE1_H
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
// Setup a Symbol Set
|
|
||||||
|
|
||||||
typedef struct EX1_Ctx{
|
|
||||||
S64 foo;
|
|
||||||
} EX1_Ctx;
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
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(){
|
|
||||||
void *image = os_this_image();
|
|
||||||
RangePtr range = self_img_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
|
|
||||||
|
|
@ -1,78 +0,0 @@
|
||||||
/*
|
|
||||||
** 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) extern 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
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,480 @@
|
||||||
|
////////////////////////////////
|
||||||
|
// Functions: ELF
|
||||||
|
|
||||||
|
// normalizing
|
||||||
|
|
||||||
|
MR4TH_SYMBOL_STATIC 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_SYMBOL_STATIC 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_SYMBOL_STATIC 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_SYMBOL_STATIC 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_SYMBOL_STATIC 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_SYMBOL_STATIC 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_SYMBOL_STATIC 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_SYMBOL_STATIC 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_SYMBOL_STATIC 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_SYMBOL_STATIC 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_SYMBOL_STATIC 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_SYMBOL_STATIC void
|
||||||
|
elf_reloca64_from_reloc32(ELF_RelocationAdd64 *dst, ELF_Relocation32 *src, ELF_Encoding src_encoding){
|
||||||
|
B32 src_big_endian = (src_encoding == ELF_Encoding_2MSB);
|
||||||
|
B32 flip_order = (src_big_endian != ARCH_BIG_ENDIAN);
|
||||||
|
dst->offset = elf_u32_decode(&src->offset, flip_order);
|
||||||
|
dst->info = elf_u32_decode(&src->info, flip_order);
|
||||||
|
dst->addend = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
MR4TH_SYMBOL_STATIC void
|
||||||
|
elf_reloca64_from_reloc64(ELF_RelocationAdd64 *dst, ELF_Relocation64 *src, ELF_Encoding src_encoding){
|
||||||
|
B32 src_big_endian = (src_encoding == ELF_Encoding_2MSB);
|
||||||
|
B32 flip_order = (src_big_endian != ARCH_BIG_ENDIAN);
|
||||||
|
dst->offset = elf_u64_decode(&src->offset, flip_order);
|
||||||
|
dst->info = elf_u64_decode(&src->info, flip_order);
|
||||||
|
dst->addend = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
MR4TH_SYMBOL_STATIC void
|
||||||
|
elf_reloca64_from_reloca32(ELF_RelocationAdd64 *dst, ELF_RelocationAdd32 *src, ELF_Encoding src_encoding){
|
||||||
|
B32 src_big_endian = (src_encoding == ELF_Encoding_2MSB);
|
||||||
|
B32 flip_order = (src_big_endian != ARCH_BIG_ENDIAN);
|
||||||
|
dst->offset = elf_u32_decode(&src->offset, flip_order);
|
||||||
|
dst->info = elf_u32_decode(&src->info, flip_order);
|
||||||
|
dst->addend = (S32)elf_u32_decode(&src->addend, flip_order);
|
||||||
|
}
|
||||||
|
|
||||||
|
MR4TH_SYMBOL_STATIC void
|
||||||
|
elf_reloca64_from_reloca64(ELF_RelocationAdd64 *dst, ELF_RelocationAdd64 *src, ELF_Encoding src_encoding){
|
||||||
|
B32 src_big_endian = (src_encoding == ELF_Encoding_2MSB);
|
||||||
|
B32 flip_order = (src_big_endian != ARCH_BIG_ENDIAN);
|
||||||
|
dst->offset = elf_u64_decode(&src->offset, flip_order);
|
||||||
|
dst->info = elf_u64_decode(&src->info, flip_order);
|
||||||
|
dst->addend = (S64)elf_u64_decode(&src->addend, flip_order);
|
||||||
|
}
|
||||||
|
|
||||||
|
// strings
|
||||||
|
|
||||||
|
MR4TH_SYMBOL_STATIC 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_SYMBOL_STATIC 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_SYMBOL_STATIC 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_SYMBOL_STATIC 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_SYMBOL_STATIC 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_SYMBOL_STATIC 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_SYMBOL_STATIC 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_SYMBOL_STATIC 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_SYMBOL_STATIC 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_SYMBOL_STATIC 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_SYMBOL_STATIC 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_SYMBOL_STATIC 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_SYMBOL_STATIC 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_SYMBOL_STATIC 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_SYMBOL_STATIC 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);
|
||||||
|
}
|
||||||
|
|
@ -302,6 +302,11 @@ X(AMDGPU, 224)\
|
||||||
X(RISCV, 243)
|
X(RISCV, 243)
|
||||||
|
|
||||||
typedef U16 ELF_MachineType;
|
typedef U16 ELF_MachineType;
|
||||||
|
enum{
|
||||||
|
#define X(N,C) ELF_MachineType_##N = C,
|
||||||
|
ELF_MachineType_XList(X)
|
||||||
|
#undef X
|
||||||
|
};
|
||||||
|
|
||||||
// elf header
|
// elf header
|
||||||
|
|
||||||
|
|
@ -660,46 +665,46 @@ typedef struct ELF_Segment64{
|
||||||
|
|
||||||
// normalizing
|
// normalizing
|
||||||
|
|
||||||
MR4TH_SYM_COMPTIME U16 elf_u16_decode(void *ptr, B32 flip);
|
MR4TH_SYMBOL_STATIC U16 elf_u16_decode(void *ptr, B32 flip);
|
||||||
MR4TH_SYM_COMPTIME U32 elf_u32_decode(void *ptr, B32 flip);
|
MR4TH_SYMBOL_STATIC U32 elf_u32_decode(void *ptr, B32 flip);
|
||||||
MR4TH_SYM_COMPTIME U64 elf_u64_decode(void *ptr, B32 flip);
|
MR4TH_SYMBOL_STATIC 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_SYMBOL_STATIC 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_SYMBOL_STATIC 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_SYMBOL_STATIC 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_SYMBOL_STATIC 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_SYMBOL_STATIC 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_SYMBOL_STATIC 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_SYMBOL_STATIC 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_SYMBOL_STATIC 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_SYMBOL_STATIC void elf_reloca64_from_reloc32(ELF_RelocationAdd64 *dst, ELF_Relocation32 *src, 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_SYMBOL_STATIC void elf_reloca64_from_reloc64(ELF_RelocationAdd64 *dst, ELF_Relocation64 *src, 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_SYMBOL_STATIC void elf_reloca64_from_reloca32(ELF_RelocationAdd64 *dst, ELF_RelocationAdd32 *src, ELF_Encoding src_encoding);
|
||||||
MR4TH_SYM_COMPTIME ELF_RelocationAdd64* elf_reloca64_from_reloca64(Arena *arena, ELF_RelocationAdd64 *src, U64 count, ELF_Encoding src_encoding);
|
MR4TH_SYMBOL_STATIC void elf_reloca64_from_reloca64(ELF_RelocationAdd64 *dst, ELF_RelocationAdd64 *src, ELF_Encoding src_encoding);
|
||||||
|
|
||||||
// strings
|
// strings
|
||||||
|
|
||||||
MR4TH_SYM_COMPTIME String8 elf_str8_from_identification_idx(ELF_IdentificationIdx idx);
|
MR4TH_SYMBOL_STATIC String8 elf_str8_from_identification_idx(ELF_IdentificationIdx idx);
|
||||||
MR4TH_SYM_COMPTIME String8 elf_str8_from_class(ELF_Class elf_class);
|
MR4TH_SYMBOL_STATIC String8 elf_str8_from_class(ELF_Class elf_class);
|
||||||
MR4TH_SYM_COMPTIME String8 elf_str8_from_encoding(ELF_Encoding elf_encoding);
|
MR4TH_SYMBOL_STATIC String8 elf_str8_from_encoding(ELF_Encoding elf_encoding);
|
||||||
MR4TH_SYM_COMPTIME String8 elf_str8_from_osabi(ELF_OsAbiExtension elf_osabi);
|
MR4TH_SYMBOL_STATIC String8 elf_str8_from_osabi(ELF_OsAbiExtension elf_osabi);
|
||||||
MR4TH_SYM_COMPTIME String8 elf_str8_from_file_type(ELF_FileType file_type);
|
MR4TH_SYMBOL_STATIC String8 elf_str8_from_file_type(ELF_FileType file_type);
|
||||||
MR4TH_SYM_COMPTIME String8 elf_str8_from_machine_type(ELF_FileType machine_type);
|
MR4TH_SYMBOL_STATIC String8 elf_str8_from_machine_type(ELF_FileType machine_type);
|
||||||
|
|
||||||
MR4TH_SYM_COMPTIME String8 elf_str8_from_section_type(ELF_SectionType section_type);
|
MR4TH_SYMBOL_STATIC 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_SYMBOL_STATIC 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_SYMBOL_STATIC String8 elf_str8_from_section_flags(Arena *arena, U32 flags);
|
||||||
|
|
||||||
MR4TH_SYM_COMPTIME String8 elf_str8_from_segment_type(ELF_SegmentType segment_type);
|
MR4TH_SYMBOL_STATIC 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_SYMBOL_STATIC 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_SYMBOL_STATIC String8 elf_str8_from_segment_flags(Arena *arena, ELF_SegmentFlags flags);
|
||||||
|
|
||||||
MR4TH_SYM_COMPTIME String8 elf_str8_from_symbol_binding(ELF_SymbolBinding bind);
|
MR4TH_SYMBOL_STATIC String8 elf_str8_from_symbol_binding(ELF_SymbolBinding bind);
|
||||||
MR4TH_SYM_COMPTIME String8 elf_str8_from_symbol_type(ELF_SymbolType type);
|
MR4TH_SYMBOL_STATIC String8 elf_str8_from_symbol_type(ELF_SymbolType type);
|
||||||
MR4TH_SYM_COMPTIME String8 elf_str8_from_symbol_vis(ELF_SymbolVis vis);
|
MR4TH_SYMBOL_STATIC String8 elf_str8_from_symbol_vis(ELF_SymbolVis vis);
|
||||||
|
|
||||||
#endif //MR4TH_ELF_H
|
#endif //MR4TH_ELF_H
|
||||||
|
|
@ -0,0 +1,412 @@
|
||||||
|
////////////////////////////////
|
||||||
|
// Elf Parse Functions
|
||||||
|
|
||||||
|
MR4TH_SYMBOL ELF_Parse*
|
||||||
|
elfp_begin(Arena *arena, String8 data){
|
||||||
|
// 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;
|
||||||
|
B32 good_headers = 0;
|
||||||
|
if (data.size >= ELF_NUM_IDENT){
|
||||||
|
elf_class = data.str[ELF_IdentificationIdx_CLASS];
|
||||||
|
elf_encoding = data.str[ELF_IdentificationIdx_DATA];
|
||||||
|
elf_version = data.str[ELF_IdentificationIdx_VERSION];
|
||||||
|
elf_ext = data.str[ELF_IdentificationIdx_OSABI];
|
||||||
|
if (data.str[0] == ELF_Magic_Byte0 &&
|
||||||
|
data.str[1] == ELF_Magic_Byte1 &&
|
||||||
|
data.str[2] == ELF_Magic_Byte2 &&
|
||||||
|
data.str[3] == ELF_Magic_Byte3 &&
|
||||||
|
elf_version == 1 &&
|
||||||
|
(elf_class == ELF_Class_32 || elf_class == ELF_Class_64) &&
|
||||||
|
(elf_encoding == ELF_Encoding_2LSB ||
|
||||||
|
elf_encoding == ELF_Encoding_2MSB)){
|
||||||
|
switch (elf_class){
|
||||||
|
case ELF_Class_32: {
|
||||||
|
if (data.size >= sizeof(ELF_Header32)){ good_headers = 1; } }break;
|
||||||
|
case ELF_Class_64: {
|
||||||
|
if (data.size >= sizeof(ELF_Header64)){ good_headers = 1; } }break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// header
|
||||||
|
void *header = 0;
|
||||||
|
U64 section_table_foff = 0;
|
||||||
|
U16 section_count = 0;
|
||||||
|
U16 section_size = 0;
|
||||||
|
U64 segment_table_foff = 0;
|
||||||
|
U16 segment_count = 0;
|
||||||
|
U16 segment_size = 0;
|
||||||
|
U16 string_section_index = 0;
|
||||||
|
|
||||||
|
if (good_headers){
|
||||||
|
switch (elf_class){
|
||||||
|
case ELF_Class_32: {
|
||||||
|
if (sizeof(ELF_Header32) <= data.size){
|
||||||
|
header = data.str;
|
||||||
|
ELF_Header32 *h = (ELF_Header32*)header;
|
||||||
|
section_table_foff = h->section_table_foff;
|
||||||
|
section_count = h->section_count;
|
||||||
|
section_size = h->section_size;
|
||||||
|
segment_table_foff = h->segment_table_foff;
|
||||||
|
segment_count = h->segment_count;
|
||||||
|
segment_size = h->segment_size;
|
||||||
|
string_section_index = h->string_section_index;
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
case ELF_Class_64: {
|
||||||
|
if (sizeof(ELF_Header64) <= data.size){
|
||||||
|
header = data.str;
|
||||||
|
ELF_Header64 *h = (ELF_Header64*)header;
|
||||||
|
section_table_foff = h->section_table_foff;
|
||||||
|
section_count = h->section_count;
|
||||||
|
section_size = h->section_size;
|
||||||
|
segment_table_foff = h->segment_table_foff;
|
||||||
|
segment_count = h->segment_count;
|
||||||
|
segment_size = h->segment_size;
|
||||||
|
string_section_index = h->string_section_index;
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sections
|
||||||
|
void *sections = 0;
|
||||||
|
if (section_count > 0 && section_table_foff + section_count*section_size <= data.size){
|
||||||
|
sections = data.str + section_table_foff;
|
||||||
|
}
|
||||||
|
|
||||||
|
// segments
|
||||||
|
void *segments = 0;
|
||||||
|
if (segment_count > 0 && segment_table_foff + segment_count*segment_size <= data.size){
|
||||||
|
segments = data.str + segment_table_foff;
|
||||||
|
}
|
||||||
|
|
||||||
|
// string table
|
||||||
|
U8 *section_strtable_first = 0;
|
||||||
|
U8 *section_strtable_opl = 0;
|
||||||
|
if (sections != 0){
|
||||||
|
U32 index = 0;
|
||||||
|
if (string_section_index != ELF_SectionIndex_UNDEF &&
|
||||||
|
string_section_index != ELF_SectionIndex_XINDEX){
|
||||||
|
index = string_section_index;
|
||||||
|
}
|
||||||
|
else if (string_section_index == ELF_SectionIndex_XINDEX){
|
||||||
|
switch (elf_class){
|
||||||
|
case ELF_Class_32: index = ((ELF_Section32*)sections)->link; break;
|
||||||
|
case ELF_Class_64: index = ((ELF_Section64*)sections)->link; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (index > 0){
|
||||||
|
U64 offset = 0;
|
||||||
|
U64 size = 0;
|
||||||
|
switch (elf_class){
|
||||||
|
case ELF_Class_32:
|
||||||
|
{
|
||||||
|
offset = ((ELF_Section32*)sections)[index].offset;
|
||||||
|
size = ((ELF_Section32*)sections)[index].size;
|
||||||
|
}break;
|
||||||
|
case ELF_Class_64:
|
||||||
|
{
|
||||||
|
offset = ((ELF_Section64*)sections)[index].offset;
|
||||||
|
size = ((ELF_Section64*)sections)[index].size;
|
||||||
|
}break;
|
||||||
|
}
|
||||||
|
if (offset < data.size && offset + size < data.size){
|
||||||
|
section_strtable_first = data.str + offset;
|
||||||
|
section_strtable_opl = data.str + offset + size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// find symtab & dynsym sections
|
||||||
|
void *symbols[ELFP_SYMBOL_TABLE_COUNT] = {0};
|
||||||
|
U32 symbol_count[ELFP_SYMBOL_TABLE_COUNT] = {0};
|
||||||
|
U8 *symbol_strtable_first[ELFP_SYMBOL_TABLE_COUNT] = {0};
|
||||||
|
U8 *symbol_strtable_opl[ELFP_SYMBOL_TABLE_COUNT] = {0};
|
||||||
|
if (sections != 0){
|
||||||
|
for (U32 i = 0; i < section_count; i += 1){
|
||||||
|
ELF_SectionType type = 0;
|
||||||
|
U64 foff = 0;
|
||||||
|
U64 opl = 0;
|
||||||
|
switch (elf_class){
|
||||||
|
case ELF_Class_32: {
|
||||||
|
ELF_Section32 *sec32 = (ELF_Section32*)sections + i;
|
||||||
|
type = sec32->type;
|
||||||
|
foff = sec32->offset;
|
||||||
|
opl = foff + sec32->size;
|
||||||
|
}break;
|
||||||
|
case ELF_Class_64: {
|
||||||
|
ELF_Section64 *sec64 = (ELF_Section64*)sections + i;
|
||||||
|
type = sec64->type;
|
||||||
|
foff = sec64->offset;
|
||||||
|
opl = foff + sec64->size;
|
||||||
|
}break;
|
||||||
|
}
|
||||||
|
U32 idx = ELFP_SYMBOL_TABLE_COUNT;
|
||||||
|
switch (type){
|
||||||
|
case ELF_SectionType_SYMTAB: idx = ELFP_SYMBOL_TABLE_symtab; break;
|
||||||
|
case ELF_SectionType_DYNSYM: idx = ELFP_SYMBOL_TABLE_dynsym; break;
|
||||||
|
}
|
||||||
|
if (idx < ELFP_SYMBOL_TABLE_COUNT &&
|
||||||
|
foff < data.size && opl < data.size){
|
||||||
|
U32 link = 0;
|
||||||
|
//U32 info = 0;
|
||||||
|
U32 count = 0;
|
||||||
|
switch (elf_class){
|
||||||
|
case ELF_Class_32: {
|
||||||
|
ELF_Section32 *sec32 = (ELF_Section32*)sections + i;
|
||||||
|
link = sec32->link;
|
||||||
|
//info = sec32->info;
|
||||||
|
count = sec32->size/sizeof(ELF_Symbol32);
|
||||||
|
}break;
|
||||||
|
case ELF_Class_64: {
|
||||||
|
ELF_Section64 *sec64 = (ELF_Section64*)sections + i;
|
||||||
|
link = sec64->link;
|
||||||
|
//info = sec64->info;
|
||||||
|
count = sec64->size/sizeof(ELF_Symbol64);
|
||||||
|
}break;
|
||||||
|
}
|
||||||
|
symbols[idx] = data.str + foff;
|
||||||
|
symbol_count[idx] = count;
|
||||||
|
if (link < section_count){
|
||||||
|
U64 strtable_off = 0;
|
||||||
|
U64 strtable_size = 0;
|
||||||
|
switch (elf_class){
|
||||||
|
case ELF_Class_32: {
|
||||||
|
ELF_Section32 *sec32 = (ELF_Section32*)sections + link;
|
||||||
|
strtable_off = sec32->offset;
|
||||||
|
strtable_size = sec32->size;
|
||||||
|
}break;
|
||||||
|
case ELF_Class_64: {
|
||||||
|
ELF_Section64 *sec64 = (ELF_Section64*)sections + link;
|
||||||
|
strtable_off = sec64->offset;
|
||||||
|
strtable_size = sec64->size;
|
||||||
|
}break;
|
||||||
|
}
|
||||||
|
if (strtable_off < data.size &&
|
||||||
|
strtable_off + strtable_size < data.size){
|
||||||
|
symbol_strtable_first[idx] = data.str + strtable_off;
|
||||||
|
symbol_strtable_opl[idx] = data.str + strtable_off + strtable_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fill result
|
||||||
|
ELF_Parse *elf = 0;
|
||||||
|
if (header != 0){
|
||||||
|
elf = push_array(arena, ELF_Parse, 1);
|
||||||
|
elf->elf_class = elf_class;
|
||||||
|
elf->encoding = elf_encoding;
|
||||||
|
elf->section_count = section_count;
|
||||||
|
elf->segment_count = segment_count;
|
||||||
|
elf->header = header;
|
||||||
|
elf->size = data.size;
|
||||||
|
elf->sections = sections;
|
||||||
|
elf->segments = segments;
|
||||||
|
elf->section_strtable_first = section_strtable_first;
|
||||||
|
elf->section_strtable_opl = section_strtable_opl;
|
||||||
|
MemoryCopyArray(elf->symbols, symbols);
|
||||||
|
MemoryCopyArray(elf->symbol_count, symbol_count);
|
||||||
|
MemoryCopyArray(elf->symbol_strtable_first, symbol_strtable_first);
|
||||||
|
MemoryCopyArray(elf->symbol_strtable_opl, symbol_strtable_opl);
|
||||||
|
}
|
||||||
|
|
||||||
|
return(elf);
|
||||||
|
}
|
||||||
|
|
||||||
|
MR4TH_SYMBOL void
|
||||||
|
elfp_header_read(ELF_Parse *elf, ELF_Header64 *out){
|
||||||
|
if (elf->header != 0){
|
||||||
|
switch (elf->elf_class){
|
||||||
|
case ELF_Class_32: {
|
||||||
|
elf_header64_from_header32(out, (ELF_Header32*)elf->header, elf->encoding);
|
||||||
|
}break;
|
||||||
|
case ELF_Class_64: {
|
||||||
|
elf_header64_from_header64(out, (ELF_Header64*)elf->header, elf->encoding);
|
||||||
|
}break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MR4TH_SYMBOL U32
|
||||||
|
elfp_section_count(ELF_Parse *elf){
|
||||||
|
U32 result = elf->section_count;
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
MR4TH_SYMBOL void
|
||||||
|
elfp_section_read(ELF_Parse *elf, U32 idx, ELF_Section64 *out){
|
||||||
|
if (elf->sections != 0 && idx < elf->section_count){
|
||||||
|
switch (elf->elf_class){
|
||||||
|
case ELF_Class_32: {
|
||||||
|
elf_section64_from_section32(out, (ELF_Section32*)elf->sections + idx, elf->encoding);
|
||||||
|
}break;
|
||||||
|
case ELF_Class_64: {
|
||||||
|
elf_section64_from_section64(out, (ELF_Section64*)elf->sections + idx, elf->encoding);
|
||||||
|
}break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MR4TH_SYMBOL String8
|
||||||
|
elfp_section_name(ELF_Parse *elf, U32 idx){
|
||||||
|
String8 result = {0};
|
||||||
|
if (elf->sections != 0 && idx < elf->section_count){
|
||||||
|
U32 name = 0;
|
||||||
|
switch (elf->elf_class){
|
||||||
|
case ELF_Class_32: name = ((ELF_Section32*)elf->sections)[idx].name; break;
|
||||||
|
case ELF_Class_64: name = ((ELF_Section64*)elf->sections)[idx].name; break;
|
||||||
|
}
|
||||||
|
result = str8_cstring_capped(elf->section_strtable_first + name,
|
||||||
|
elf->section_strtable_opl);
|
||||||
|
}
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
MR4TH_SYMBOL U32
|
||||||
|
elfp_segment_count(ELF_Parse *elf){
|
||||||
|
U32 result = elf->segment_count;
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
MR4TH_SYMBOL void
|
||||||
|
elfp_segment_read(ELF_Parse *elf, U32 idx, ELF_Segment64 *out){
|
||||||
|
if (elf->segments != 0 && idx < elf->segment_count){
|
||||||
|
switch (elf->elf_class){
|
||||||
|
case ELF_Class_32: {
|
||||||
|
elf_segment64_from_segment32(out, (ELF_Segment32*)elf->segments + idx, elf->encoding);
|
||||||
|
}break;
|
||||||
|
case ELF_Class_64: {
|
||||||
|
elf_segment64_from_segment64(out, (ELF_Segment64*)elf->segments + idx, elf->encoding);
|
||||||
|
}break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MR4TH_SYMBOL U32
|
||||||
|
elfp_symbol_count(ELF_Parse *elf, U32 table){
|
||||||
|
U32 result = 0;
|
||||||
|
if (table < ELFP_SYMBOL_TABLE_COUNT){
|
||||||
|
result = elf->symbol_count[table];
|
||||||
|
}
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
MR4TH_SYMBOL void
|
||||||
|
elfp_symbol_read(ELF_Parse *elf, U32 table, U32 idx, ELF_Symbol64 *out){
|
||||||
|
if (table < ELFP_SYMBOL_TABLE_COUNT){
|
||||||
|
void *symbols = elf->symbols[table];
|
||||||
|
switch (elf->elf_class){
|
||||||
|
case ELF_Class_32: {
|
||||||
|
elf_symbol64_from_symbol32(out, (ELF_Symbol32*)symbols + idx, elf->encoding);
|
||||||
|
}break;
|
||||||
|
case ELF_Class_64: {
|
||||||
|
elf_symbol64_from_symbol64(out, (ELF_Symbol64*)symbols + idx, elf->encoding);
|
||||||
|
}break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MR4TH_SYMBOL String8
|
||||||
|
elfp_symbol_name(ELF_Parse *elf, U32 table, U32 idx){
|
||||||
|
String8 result = {0};
|
||||||
|
if (table < ELFP_SYMBOL_TABLE_COUNT){
|
||||||
|
void *s = elf->symbols[table];
|
||||||
|
U8 *string_table_first = elf->symbol_strtable_first[table];
|
||||||
|
U8 *string_table_opl = elf->symbol_strtable_opl[table];
|
||||||
|
U32 name = 0;
|
||||||
|
switch (elf->elf_class){
|
||||||
|
case ELF_Class_32: name = ((ELF_Symbol32*)s)[idx].name; break;
|
||||||
|
case ELF_Class_64: name = ((ELF_Symbol64*)s)[idx].name; break;
|
||||||
|
}
|
||||||
|
if (string_table_first != 0){
|
||||||
|
result = str8_cstring_capped(string_table_first + name,
|
||||||
|
string_table_opl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
MR4TH_SYMBOL U32
|
||||||
|
elfp_relocs_count(ELF_Parse *elf, U32 secidx){
|
||||||
|
U32 result = 0;
|
||||||
|
if (elf->sections != 0 && secidx < elf->section_count){
|
||||||
|
switch (elf->elf_class){
|
||||||
|
case ELF_Class_32: {
|
||||||
|
ELF_Section32 *sec32 = ((ELF_Section32*)elf->sections) + secidx;
|
||||||
|
switch (sec32->type){
|
||||||
|
case ELF_SectionType_REL:
|
||||||
|
result = sec32->size/sizeof(ELF_Relocation32); break;
|
||||||
|
case ELF_SectionType_RELA:
|
||||||
|
result = sec32->size/sizeof(ELF_RelocationAdd32); break;
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
case ELF_Class_64: {
|
||||||
|
ELF_Section64 *sec64 = ((ELF_Section64*)elf->sections) + secidx;
|
||||||
|
switch (sec64->type){
|
||||||
|
case ELF_SectionType_REL:
|
||||||
|
result = sec64->size/sizeof(ELF_Relocation64); break;
|
||||||
|
case ELF_SectionType_RELA:
|
||||||
|
result = sec64->size/sizeof(ELF_RelocationAdd64); break;
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
MR4TH_SYMBOL void
|
||||||
|
elfp_relocs_read(ELF_Parse *elf, U32 secidx, U32 relocidx, ELF_RelocationAdd64 *out){
|
||||||
|
if (elf->sections != 0 && secidx < elf->section_count){
|
||||||
|
switch (elf->elf_class){
|
||||||
|
case ELF_Class_32: {
|
||||||
|
ELF_Section32 *sec32 = ((ELF_Section32*)elf->sections) + secidx;
|
||||||
|
U64 opl = ClampTop(sec32->offset + sec32->size, elf->size);
|
||||||
|
U64 size = opl - sec32->offset;
|
||||||
|
switch (sec32->type){
|
||||||
|
case ELF_SectionType_REL: {
|
||||||
|
ELF_Relocation32 *relocs = (ELF_Relocation32*)((U8*)elf->header + sec32->offset);
|
||||||
|
U32 count = sec32->size/sizeof(*relocs);
|
||||||
|
if (relocidx < count){
|
||||||
|
elf_reloca64_from_reloc32(out, relocs + relocidx, elf->encoding);
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
case ELF_SectionType_RELA: {
|
||||||
|
ELF_RelocationAdd32 *relocs = (ELF_RelocationAdd32*)((U8*)elf->header + sec32->offset);
|
||||||
|
U32 count = sec32->size/sizeof(*relocs);
|
||||||
|
if (relocidx < count){
|
||||||
|
elf_reloca64_from_reloca32(out, relocs + relocidx, elf->encoding);
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
case ELF_Class_64: {
|
||||||
|
ELF_Section64 *sec64 = ((ELF_Section64*)elf->sections) + secidx;
|
||||||
|
U64 opl = ClampTop(sec64->offset + sec64->size, elf->size);
|
||||||
|
U64 size = opl - sec64->offset;
|
||||||
|
switch (sec64->type){
|
||||||
|
case ELF_SectionType_REL: {
|
||||||
|
ELF_Relocation64 *relocs = (ELF_Relocation64*)((U8*)elf->header + sec64->offset);
|
||||||
|
U32 count = sec64->size/sizeof(*relocs);
|
||||||
|
if (relocidx < count){
|
||||||
|
elf_reloca64_from_reloc64(out, relocs + relocidx, elf->encoding);
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
case ELF_SectionType_RELA: {
|
||||||
|
ELF_RelocationAdd64 *relocs = (ELF_RelocationAdd64*)((U8*)elf->header + sec64->offset);
|
||||||
|
U32 count = sec64->size/sizeof(*relocs);
|
||||||
|
if (relocidx < count){
|
||||||
|
elf_reloca64_from_reloca64(out, relocs + relocidx, elf->encoding);
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
#ifndef MR4TH_ELF_PARSE_H
|
||||||
|
#define MR4TH_ELF_PARSE_H
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// Elf Parse Types
|
||||||
|
|
||||||
|
#define ELFP_SYMBOL_TABLE_symtab 0
|
||||||
|
#define ELFP_SYMBOL_TABLE_dynsym 1
|
||||||
|
#define ELFP_SYMBOL_TABLE_COUNT 2
|
||||||
|
|
||||||
|
typedef struct ELF_Parse{
|
||||||
|
ELF_Class elf_class;
|
||||||
|
ELF_Encoding encoding;
|
||||||
|
U32 section_count;
|
||||||
|
U32 segment_count;
|
||||||
|
void *header;
|
||||||
|
U64 size;
|
||||||
|
void *sections;
|
||||||
|
void *segments;
|
||||||
|
U8 *section_strtable_first;
|
||||||
|
U8 *section_strtable_opl;
|
||||||
|
void *symbols[ELFP_SYMBOL_TABLE_COUNT];
|
||||||
|
U32 symbol_count[ELFP_SYMBOL_TABLE_COUNT];
|
||||||
|
U8 *symbol_strtable_first[ELFP_SYMBOL_TABLE_COUNT];
|
||||||
|
U8 *symbol_strtable_opl[ELFP_SYMBOL_TABLE_COUNT];
|
||||||
|
} ELF_Parse;
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// Elf Parse Functions
|
||||||
|
|
||||||
|
MR4TH_SYMBOL ELF_Parse* elfp_begin(Arena *arena, String8 data);
|
||||||
|
|
||||||
|
MR4TH_SYMBOL void elfp_header_read(ELF_Parse *elf, ELF_Header64 *out);
|
||||||
|
|
||||||
|
MR4TH_SYMBOL U32 elfp_section_count(ELF_Parse *elf);
|
||||||
|
MR4TH_SYMBOL void elfp_section_read(ELF_Parse *elf, U32 idx, ELF_Section64 *out);
|
||||||
|
MR4TH_SYMBOL String8 elfp_section_name(ELF_Parse *elf, U32 idx);
|
||||||
|
|
||||||
|
MR4TH_SYMBOL U32 elfp_segment_count(ELF_Parse *elf);
|
||||||
|
MR4TH_SYMBOL void elfp_segment_read(ELF_Parse *elf, U32 idx, ELF_Segment64 *out);
|
||||||
|
|
||||||
|
MR4TH_SYMBOL U32 elfp_symbol_count(ELF_Parse *elf, U32 table);
|
||||||
|
MR4TH_SYMBOL void elfp_symbol_read(ELF_Parse *elf, U32 table, U32 idx, ELF_Symbol64 *out);
|
||||||
|
MR4TH_SYMBOL String8 elfp_symbol_name(ELF_Parse *elf, U32 table, U32 idx);
|
||||||
|
|
||||||
|
MR4TH_SYMBOL U32 elfp_relocs_count(ELF_Parse *elf, U32 secidx);
|
||||||
|
MR4TH_SYMBOL void elfp_relocs_read(ELF_Parse *elf, U32 secidx, U32 relocidx, ELF_RelocationAdd64 *out);
|
||||||
|
|
||||||
|
#endif //MR4TH_ELF_PARSE_H
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,294 @@
|
||||||
|
////////////////////////////////
|
||||||
|
// Functions: Command Line Parsing
|
||||||
|
|
||||||
|
MR4TH_SYMBOL MR4TH_READ_ONLY
|
||||||
|
CMDLN_Params cmdln__params_nil = {0};
|
||||||
|
|
||||||
|
#define cmdln_params_nil (CMDLN_Params*)(&cmdln__params_nil)
|
||||||
|
|
||||||
|
MR4TH_SYMBOL CMDLN*
|
||||||
|
cmdln_from_args(Arena *arena, String8List *args){
|
||||||
|
CMDLN *cmdln = push_array(arena, CMDLN, 1);
|
||||||
|
cmdln->raw = str8_list_copy(arena, args);
|
||||||
|
|
||||||
|
String8Node *node = cmdln->raw.first;
|
||||||
|
|
||||||
|
// first string is 'program'
|
||||||
|
if (node != 0){
|
||||||
|
cmdln->program = node->string;
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// consume string nodes
|
||||||
|
B32 forced_input = 0;
|
||||||
|
for (;node != 0;){
|
||||||
|
String8 string = str8_skip_chop_whitespace(node->string);
|
||||||
|
node = node->next;
|
||||||
|
|
||||||
|
// check if argument is a flag
|
||||||
|
B32 is_flag = 0;
|
||||||
|
if (!forced_input){
|
||||||
|
is_flag = (string.size != 0 && string.str[0] == '-');
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse flag
|
||||||
|
if (is_flag){
|
||||||
|
|
||||||
|
// long flag
|
||||||
|
B32 is_long_flag = (string.size > 1 && string.str[1] == '-');
|
||||||
|
if (is_long_flag){
|
||||||
|
|
||||||
|
// end 'normal' mode
|
||||||
|
B32 double_dash = (string.size == 2);
|
||||||
|
if (double_dash){
|
||||||
|
forced_input = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse long flag
|
||||||
|
if (!double_dash){
|
||||||
|
String8 flag_whole = str8_skip(string, 2);
|
||||||
|
|
||||||
|
// parameter delimter
|
||||||
|
U64 delim = flag_whole.size;
|
||||||
|
for (U8 *ptr = flag_whole.str, *opl = flag_whole.str + flag_whole.size;
|
||||||
|
ptr < opl; ptr += 1){
|
||||||
|
if (*ptr == '=' || *ptr == ':'){
|
||||||
|
delim = (U64)(ptr - flag_whole.str);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// split flag at delimiter
|
||||||
|
String8 flag_name = str8_prefix(flag_whole, delim);
|
||||||
|
String8 flag_param = str8_skip(flag_whole, delim + 1);
|
||||||
|
|
||||||
|
// if have a param delimiter at end
|
||||||
|
// then use the next argument as the flag_param
|
||||||
|
if (delim == flag_whole.size - 1){
|
||||||
|
if (node != 0){
|
||||||
|
flag_param = node->string;
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse parameters
|
||||||
|
CMDLN_Params *params = cmdln_params_from_string(arena, flag_param);
|
||||||
|
|
||||||
|
// store flag node
|
||||||
|
{
|
||||||
|
CMDLN_Node *cmdlnnode = push_array(arena, CMDLN_Node, 1);
|
||||||
|
SLLQueuePush(cmdln->first, cmdln->last, cmdlnnode);
|
||||||
|
cmdlnnode->string = flag_name;
|
||||||
|
cmdlnnode->params = params;
|
||||||
|
cmdln->flag_count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// short flags
|
||||||
|
if (!is_long_flag){
|
||||||
|
String8 short_flags = str8_skip(string, 1);
|
||||||
|
|
||||||
|
U8 *flag = short_flags.str;
|
||||||
|
U8 *flagopl = short_flags.str + short_flags.size;
|
||||||
|
for (; flag < flagopl; flag += 1){
|
||||||
|
U8 *flagptr = flag;
|
||||||
|
|
||||||
|
// check for parameters
|
||||||
|
String8 flag_param = {0};
|
||||||
|
if (flag + 1 < flagopl &&
|
||||||
|
(flag[1] == '=' || flag[1] == ':')){
|
||||||
|
flag_param = str8_range(flag + 2, flagopl);
|
||||||
|
if (flag_param.size == 0){
|
||||||
|
if (node != 0){
|
||||||
|
flag_param = node->string;
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// kill the flag loop after finding parameters
|
||||||
|
flag = flagopl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse parameters
|
||||||
|
CMDLN_Params *params = cmdln_params_from_string(arena, flag_param);
|
||||||
|
|
||||||
|
// store flag node
|
||||||
|
{
|
||||||
|
CMDLN_Node *cmdlnnode = push_array(arena, CMDLN_Node, 1);
|
||||||
|
SLLQueuePush(cmdln->first, cmdln->last, cmdlnnode);
|
||||||
|
cmdlnnode->string = CLiteral(String8){flagptr, 1};
|
||||||
|
cmdlnnode->params = params;
|
||||||
|
cmdln->flag_count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse input
|
||||||
|
if (!is_flag){
|
||||||
|
String8 input_string = string;
|
||||||
|
|
||||||
|
// store input node
|
||||||
|
{
|
||||||
|
CMDLN_Node *cmdlnnode = push_array(arena, CMDLN_Node, 1);
|
||||||
|
SLLQueuePush(cmdln->first, cmdln->last, cmdlnnode);
|
||||||
|
cmdlnnode->string = input_string;
|
||||||
|
cmdln->input_count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// pointer arrays
|
||||||
|
cmdln->inputs = push_array(arena, CMDLN_Node*, cmdln->input_count);
|
||||||
|
cmdln->flags = push_array(arena, CMDLN_Node*, cmdln->flag_count);
|
||||||
|
{
|
||||||
|
CMDLN_Node **inputptr = cmdln->inputs;
|
||||||
|
CMDLN_Node **flagptr = cmdln->flags;
|
||||||
|
for (CMDLN_Node *node = cmdln->first;
|
||||||
|
node != 0;
|
||||||
|
node = node->next){
|
||||||
|
if (node->params == 0){
|
||||||
|
*inputptr = node;
|
||||||
|
inputptr += 1;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
*flagptr = node;
|
||||||
|
flagptr += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return(cmdln);
|
||||||
|
}
|
||||||
|
|
||||||
|
MR4TH_SYMBOL CMDLN_Params*
|
||||||
|
cmdln_params_from_string(Arena *arena, String8 flag_param){
|
||||||
|
CMDLN_Params *params = cmdln_params_nil;
|
||||||
|
if (flag_param.size > 0){
|
||||||
|
params = push_array(arena, CMDLN_Params, 1);
|
||||||
|
params->raw = flag_param;
|
||||||
|
params->list = str8_split(arena, flag_param, (U8*)",", 1);
|
||||||
|
}
|
||||||
|
return(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
MR4TH_SYMBOL U64
|
||||||
|
cmdln_input_count(CMDLN *cmdln){
|
||||||
|
return(cmdln->input_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
MR4TH_SYMBOL String8
|
||||||
|
cmdln_input_from_idx(CMDLN *cmdln, U64 idx){
|
||||||
|
String8 result = {0};
|
||||||
|
if (idx < cmdln->input_count){
|
||||||
|
result = cmdln->inputs[idx]->string;
|
||||||
|
}
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
MR4TH_SYMBOL U64
|
||||||
|
cmdln_flag_count(CMDLN *cmdln){
|
||||||
|
return(cmdln->flag_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
MR4TH_SYMBOL CMDLN_Flag*
|
||||||
|
cmdln_flag_from_idx(CMDLN *cmdln, U64 idx){
|
||||||
|
CMDLN_Flag *result = 0;
|
||||||
|
if (idx < cmdln->flag_count){
|
||||||
|
result = cmdln->flags[idx];
|
||||||
|
}
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
MR4TH_SYMBOL CMDLN_Params*
|
||||||
|
cmdln_get_params(CMDLN *cmdln, String8 flagstr, char abbrev){
|
||||||
|
CMDLN_Params *result = 0;
|
||||||
|
for (CMDLN_Node *node = cmdln->first;
|
||||||
|
node != 0;
|
||||||
|
node = node->next){
|
||||||
|
if (node->params != 0){
|
||||||
|
if (str8_match(flagstr, node->string, 0) ||
|
||||||
|
(node->string.size == 1 && node->string.str[0] == (U8)abbrev)){
|
||||||
|
result = node->params;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
MR4TH_SYMBOL B32
|
||||||
|
cmdln_has_flag(CMDLN *cmdln, String8 flagstr, char abbrev){
|
||||||
|
CMDLN_Params *params = cmdln_get_params(cmdln, flagstr, abbrev);
|
||||||
|
B32 result = (params != 0);
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
MR4TH_SYMBOL String8
|
||||||
|
cmdln_get_str8(CMDLN *cmdln, String8 flagstr, char abbrev){
|
||||||
|
CMDLN_Params *params = cmdln_get_params(cmdln, flagstr, abbrev);
|
||||||
|
String8 result = {0};
|
||||||
|
if (params != 0){
|
||||||
|
result = params->raw;
|
||||||
|
}
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
MR4TH_SYMBOL S64
|
||||||
|
cmdln_get_s64(CMDLN *cmdln, String8 flagstr, char abbrev){
|
||||||
|
String8 str = cmdln_get_str8(cmdln, flagstr, abbrev);
|
||||||
|
S64 result = cmdln_s64_from_str8(str);
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
MR4TH_SYMBOL F64
|
||||||
|
cmdln_get_f64(CMDLN *cmdln, String8 flagstr, char abbrev){
|
||||||
|
String8 str = cmdln_get_str8(cmdln, flagstr, abbrev);
|
||||||
|
F64 result = cmdln_f64_from_str8(str);
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
MR4TH_SYMBOL S64
|
||||||
|
cmdln_s64_from_str8(String8 valstr){
|
||||||
|
S64 result = s64_from_str8_c_syntax(valstr);
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
MR4TH_SYMBOL F64
|
||||||
|
cmdln_f64_from_str8(String8 valstr){
|
||||||
|
F64 result = f64_from_str8(valstr);
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
MR4TH_SYMBOL void
|
||||||
|
cmdln_dump(Arena *arena, String8List *out, CMDLN *cmdln, U32 indent){
|
||||||
|
// raw
|
||||||
|
str8_list_pushf(arena, out, "%Nraw:\n", indent);
|
||||||
|
for (String8Node *node = cmdln->raw.first;
|
||||||
|
node != 0;
|
||||||
|
node = node->next){
|
||||||
|
str8_list_pushf(arena, out, "%N%S\n", indent + 1, node->string);
|
||||||
|
}
|
||||||
|
|
||||||
|
// program
|
||||||
|
str8_list_pushf(arena, out, "%Nprogram: %S\n", indent, cmdln->program);
|
||||||
|
|
||||||
|
// input nodes
|
||||||
|
str8_list_pushf(arena, out, "%Nnodes:\n", indent);
|
||||||
|
for (CMDLN_Node *cmdlnnode = cmdln->first;
|
||||||
|
cmdlnnode != 0;
|
||||||
|
cmdlnnode = cmdlnnode->next){
|
||||||
|
if (cmdlnnode->params == 0){
|
||||||
|
str8_list_pushf(arena, out, "%N[input] %S\n", indent + 1, cmdlnnode->string);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
str8_list_pushf(arena, out, "%N[flag ] %S\n", indent + 1, cmdlnnode->string);
|
||||||
|
for (String8Node *node = cmdlnnode->params->list.first;
|
||||||
|
node != 0;
|
||||||
|
node = node->next){
|
||||||
|
str8_list_pushf(arena, out, "%N[param] %S\n", indent + 2, node->string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
#ifndef MR4TH_CMDLN_H
|
||||||
|
#define MR4TH_CMDLN_H
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// Types: Command Line Parsing
|
||||||
|
|
||||||
|
typedef struct CMDLN_Params{
|
||||||
|
String8 raw;
|
||||||
|
String8List list;
|
||||||
|
} CMDLN_Params;
|
||||||
|
|
||||||
|
typedef struct CMDLN_Node{
|
||||||
|
struct CMDLN_Node *next;
|
||||||
|
String8 string;
|
||||||
|
CMDLN_Params *params;
|
||||||
|
// (params == 0 ) -> 'input' (not a flag)
|
||||||
|
// (params != 0 ) -> flag
|
||||||
|
// (params == nil) -> flag has no parameters
|
||||||
|
} CMDLN_Node;
|
||||||
|
|
||||||
|
typedef CMDLN_Node CMDLN_Flag;
|
||||||
|
|
||||||
|
typedef struct CMDLN{
|
||||||
|
String8List raw;
|
||||||
|
String8 program;
|
||||||
|
CMDLN_Node *first;
|
||||||
|
CMDLN_Node *last;
|
||||||
|
U64 input_count;
|
||||||
|
U64 flag_count;
|
||||||
|
CMDLN_Node **inputs;
|
||||||
|
CMDLN_Node **flags;
|
||||||
|
} CMDLN;
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// Functions: Command Line Parsing
|
||||||
|
|
||||||
|
MR4TH_SYMBOL CMDLN* cmdln_from_args(Arena *arena, String8List *args);
|
||||||
|
MR4TH_SYMBOL CMDLN_Params* cmdln_params_from_string(Arena *arena, String8 flag_param);
|
||||||
|
|
||||||
|
MR4TH_SYMBOL U64 cmdln_input_count(CMDLN *cmdln);
|
||||||
|
MR4TH_SYMBOL String8 cmdln_input_from_idx(CMDLN *cmdln, U64 idx);
|
||||||
|
|
||||||
|
MR4TH_SYMBOL U64 cmdln_flag_count(CMDLN *cmdln);
|
||||||
|
MR4TH_SYMBOL CMDLN_Flag* cmdln_flag_from_idx(CMDLN *cmdln, U64 idx);
|
||||||
|
|
||||||
|
MR4TH_SYMBOL CMDLN_Params* cmdln_get_params(CMDLN *cmdln, String8 flagstr, char abbrev);
|
||||||
|
MR4TH_SYMBOL B32 cmdln_has_flag(CMDLN *cmdln, String8 flagstr, char abbrev);
|
||||||
|
MR4TH_SYMBOL String8 cmdln_get_str8(CMDLN *cmdln, String8 flagstr, char abbrev);
|
||||||
|
MR4TH_SYMBOL S64 cmdln_get_s64(CMDLN *cmdln, String8 flagstr, char abbrev);
|
||||||
|
MR4TH_SYMBOL F64 cmdln_get_f64(CMDLN *cmdln, String8 flagstr, char abbrev);
|
||||||
|
|
||||||
|
MR4TH_SYMBOL S64 cmdln_s64_from_str8(String8 valstr);
|
||||||
|
MR4TH_SYMBOL F64 cmdln_f64_from_str8(String8 valstr);
|
||||||
|
|
||||||
|
MR4TH_SYMBOL void cmdln_dump(Arena *arena, String8List *out, CMDLN *cmdln, U32 indent);
|
||||||
|
|
||||||
|
/* TODO:
|
||||||
|
** [ ] fuzz
|
||||||
|
** [ ] built in parser diagnostics
|
||||||
|
** [ ] built in misuse feedback
|
||||||
|
** [ ] help structurer
|
||||||
|
*/
|
||||||
|
|
||||||
|
#endif //MR4TH_CMDLN_H
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
////////////////////////////////
|
||||||
|
// Functions: File Handle Printf
|
||||||
|
|
||||||
|
MR4TH_SYMBOL void
|
||||||
|
m4_printf(char *fmt, ...){
|
||||||
|
ArenaTemp scratch = arena_get_scratch(0, 0);
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
String8 str = str8_pushfv(scratch.arena, fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
fwrite(str.str, 1, str.size, stdout);
|
||||||
|
arena_release_scratch(&scratch);
|
||||||
|
}
|
||||||
|
|
||||||
|
MR4TH_SYMBOL void
|
||||||
|
m4_fprintf(FILE *file, char *fmt, ...){
|
||||||
|
ArenaTemp scratch = arena_get_scratch(0, 0);
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
String8 str = str8_pushfv(scratch.arena, fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
fwrite(str.str, 1, str.size, file);
|
||||||
|
arena_release_scratch(&scratch);
|
||||||
|
}
|
||||||
|
|
||||||
|
MR4TH_SYMBOL void
|
||||||
|
m4_print_str8list(String8List *out){
|
||||||
|
m4_fprint_str8list(stdout, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
MR4TH_SYMBOL void
|
||||||
|
m4_fprint_str8list(FILE *file, String8List *out){
|
||||||
|
for (String8Node *node = out->first;
|
||||||
|
node != 0;
|
||||||
|
node = node->next){
|
||||||
|
fwrite(node->string.str, node->string.size, 1, file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(allen): integrate here
|
||||||
|
MR4TH_SYMBOL_STATIC void
|
||||||
|
stream_fprint(FILE *file, STREAM *stream){
|
||||||
|
for (STREAM_Node *node = stream->first_node;
|
||||||
|
node != 0;
|
||||||
|
node = node->next){
|
||||||
|
fwrite(node->data, 1, node->size, file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// LogToProc for (FILE*)
|
||||||
|
|
||||||
|
MR4TH_SYMBOL void
|
||||||
|
cstd_logto_file_handle(void *uptr, String8 str){
|
||||||
|
fwrite(str.str, 1, str.size, (FILE*)uptr);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
#ifndef MR4TH_STDIO_H
|
||||||
|
#define MR4TH_STDIO_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// Functions: File Handle Printf
|
||||||
|
|
||||||
|
MR4TH_SYMBOL void m4_printf(char *fmt, ...);
|
||||||
|
MR4TH_SYMBOL void m4_fprintf(FILE *file, char *fmt, ...);
|
||||||
|
|
||||||
|
MR4TH_SYMBOL void m4_print_str8list(String8List *out);
|
||||||
|
MR4TH_SYMBOL void m4_fprint_str8list(FILE *file, String8List *out);
|
||||||
|
|
||||||
|
// TODO(allen): integrate to this layer
|
||||||
|
MR4TH_SYMBOL void stream_fprint(FILE *file, STREAM *stream);
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// LogToProc for (FILE*)
|
||||||
|
|
||||||
|
MR4TH_SYMBOL void cstd_logto_file_handle(void *uptr, String8 str);
|
||||||
|
|
||||||
|
#endif //MR4TH_STDIO_H
|
||||||
|
|
@ -0,0 +1,146 @@
|
||||||
|
/*
|
||||||
|
** Symbol Set Link Script Generator for ld
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "mr4th_base.h"
|
||||||
|
#include "mr4th_cmdln.h"
|
||||||
|
#include "exefmt/elf/mr4th_elf.h"
|
||||||
|
#include "exefmt/elf/mr4th_elf.parse.h"
|
||||||
|
|
||||||
|
#include "mr4th_stdio.h"
|
||||||
|
|
||||||
|
#include "mr4th_base.c"
|
||||||
|
#include "mr4th_cmdln.c"
|
||||||
|
#include "exefmt/elf/mr4th_elf.c"
|
||||||
|
#include "exefmt/elf/mr4th_elf.parse.c"
|
||||||
|
|
||||||
|
#include "mr4th_stdio.c"
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// 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();
|
||||||
|
CMDLN *cmdln = cmdln_from_args(arena, &command_line_args);
|
||||||
|
|
||||||
|
String8 output_file_name = cmdln_get_str8(cmdln, str8_lit("out"), 'o');
|
||||||
|
if (output_file_name.size == 0){
|
||||||
|
output_file_name = str8_lit("sy.ld");
|
||||||
|
}
|
||||||
|
|
||||||
|
// symbol set names
|
||||||
|
String8List symbol_set_names_list = {0};
|
||||||
|
BUFFER buckets;
|
||||||
|
buffer_alloc(&buckets, GB(64));
|
||||||
|
hash_buckets_init(&buckets, 512);
|
||||||
|
|
||||||
|
for (U32 input_idx = 0;; input_idx += 1){
|
||||||
|
// load input file
|
||||||
|
String8 input_file_name = cmdln_input_from_idx(cmdln, input_idx);
|
||||||
|
if (input_file_name.size == 0){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
String8 input_data = os_file_read(arena, input_file_name);
|
||||||
|
|
||||||
|
// parse
|
||||||
|
ELF_Parse *parse = elfp_begin(arena, input_data);
|
||||||
|
if (parse != 0){
|
||||||
|
|
||||||
|
// process sections
|
||||||
|
U32 section_count = elfp_section_count(parse);
|
||||||
|
for (U32 i = 0; i < section_count; i += 1){
|
||||||
|
String8 secname = elfp_section_name(parse, i);
|
||||||
|
if (secname.size >= 4 &&
|
||||||
|
str8_match(secname, str8_lit(".sy."), StringMatchFlag_PrefixMatch)){
|
||||||
|
String8 syname = str8_skip(secname, 4);
|
||||||
|
U64 hash = str8_hash(syname);
|
||||||
|
B32 match = 0;
|
||||||
|
for (HASH_Node *hash_node = hash_buckets_first(&buckets, hash);
|
||||||
|
hash_node != 0;
|
||||||
|
hash_node = hash_node->next){
|
||||||
|
if (hash_node->hash == hash){
|
||||||
|
String8Node *node = (String8Node*)PtrFromInt(hash_node->val);
|
||||||
|
if (str8_match(node->string, syname, 0)){
|
||||||
|
match = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!match){
|
||||||
|
str8_list_push(arena, &symbol_set_names_list, syname);
|
||||||
|
hash_buckets_expand(&buckets, symbol_set_names_list.node_count);
|
||||||
|
hash_buckets_insert(arena, &buckets, hash,
|
||||||
|
IntFromPtr(symbol_set_names_list.last));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// process symbols
|
||||||
|
U32 symbol_count = elfp_symbol_count(parse, ELFP_SYMBOL_TABLE_symtab);
|
||||||
|
for (U32 i = 0; i < symbol_count; i += 1){
|
||||||
|
String8 name = elfp_symbol_name(parse, ELFP_SYMBOL_TABLE_symtab, i);
|
||||||
|
|
||||||
|
String8 syname = {0};
|
||||||
|
if (str8_match(name, str8_lit("syfirst__"), StringMatchFlag_PrefixMatch)){
|
||||||
|
syname = str8_skip(name, 9);
|
||||||
|
}
|
||||||
|
else if (str8_match(name, str8_lit("syopl__"), StringMatchFlag_PrefixMatch)){
|
||||||
|
syname = str8_skip(name, 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (syname.size != 0){
|
||||||
|
U64 hash = str8_hash(syname);
|
||||||
|
B32 match = 0;
|
||||||
|
for (HASH_Node *hash_node = hash_buckets_first(&buckets, hash);
|
||||||
|
hash_node != 0;
|
||||||
|
hash_node = hash_node->next){
|
||||||
|
if (hash_node->hash == hash){
|
||||||
|
String8Node *node = (String8Node*)PtrFromInt(hash_node->val);
|
||||||
|
if (str8_match(node->string, syname, 0)){
|
||||||
|
match = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!match){
|
||||||
|
str8_list_push(arena, &symbol_set_names_list, syname);
|
||||||
|
hash_buckets_expand(&buckets, symbol_set_names_list.node_count);
|
||||||
|
hash_buckets_insert(arena, &buckets, hash,
|
||||||
|
IntFromPtr(symbol_set_names_list.last));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// print output linker script
|
||||||
|
STREAM *stream = stream_new();
|
||||||
|
|
||||||
|
stream_printf(stream,
|
||||||
|
"SECTIONS {\n"
|
||||||
|
" .sy : {\n");
|
||||||
|
|
||||||
|
for (String8Node *node = symbol_set_names_list.first;
|
||||||
|
node != 0; node = node->next){
|
||||||
|
stream_printf(stream, " syfirst__%S = .; *(.sy.%S); syopl__%S = .;\n",
|
||||||
|
&node->string, &node->string, &node->string);
|
||||||
|
}
|
||||||
|
|
||||||
|
stream_printf(stream,
|
||||||
|
" }\n"
|
||||||
|
"}\n"
|
||||||
|
"INSERT AFTER .data;\n");
|
||||||
|
|
||||||
|
os_file_write_stream(output_file_name, stream);
|
||||||
|
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,269 @@
|
||||||
|
#if !defined(SY__BASE_H)
|
||||||
|
#define SY__BASE_H
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// Context Cracking
|
||||||
|
|
||||||
|
// untangle compiler, os, & architecture
|
||||||
|
#if defined(__clang__)
|
||||||
|
# define SY__COMPILER_CLANG 1
|
||||||
|
|
||||||
|
# if defined(_WIN32)
|
||||||
|
# define SY__OS_WINDOWS 1
|
||||||
|
# elif defined(__gnu_linux__)
|
||||||
|
# define SY__OS_LINUX 1
|
||||||
|
# elif defined(__APPLE__) && defined(__MACH__)
|
||||||
|
# define SY__OS_MAC 1
|
||||||
|
# else
|
||||||
|
# error missing OS detection
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# if defined(__amd64__)
|
||||||
|
# define SY__ARCH_X64 1
|
||||||
|
// TODO(allen): verify this works on clang
|
||||||
|
# elif defined(__i386__)
|
||||||
|
# define SY__ARCH_X86 1
|
||||||
|
// TODO(allen): verify this works on clang
|
||||||
|
# elif defined(__arm__)
|
||||||
|
# define SY__ARCH_ARM 1
|
||||||
|
// TODO(allen): verify this works on clang
|
||||||
|
# elif defined(__aarch64__)
|
||||||
|
# define SY__ARCH_ARM64 1
|
||||||
|
# else
|
||||||
|
# error missing SY__ARCH detection
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
# define SY__COMPILER_CL 1
|
||||||
|
|
||||||
|
# if defined(_WIN32)
|
||||||
|
# define SY__OS_WINDOWS 1
|
||||||
|
# else
|
||||||
|
# error missing OS detection
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# if defined(_M_AMD64)
|
||||||
|
# define SY__ARCH_X64 1
|
||||||
|
# elif defined(_M_I86)
|
||||||
|
# define SY__ARCH_X86 1
|
||||||
|
# elif defined(_M_ARM)
|
||||||
|
# define SY__ARCH_ARM 1
|
||||||
|
// TODO(allen): ARM64?
|
||||||
|
# else
|
||||||
|
# error missing SY__ARCH detection
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
# define SY__COMPILER_GCC 1
|
||||||
|
|
||||||
|
# if defined(_WIN32)
|
||||||
|
# define SY__OS_WINDOWS 1
|
||||||
|
# elif defined(__gnu_linux__)
|
||||||
|
# define SY__OS_LINUX 1
|
||||||
|
# elif defined(__APPLE__) && defined(__MACH__)
|
||||||
|
# define SY__OS_MAC 1
|
||||||
|
# else
|
||||||
|
# error missing OS detection
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# if defined(__amd64__)
|
||||||
|
# define SY__ARCH_X64 1
|
||||||
|
# elif defined(__i386__)
|
||||||
|
# define SY__ARCH_X86 1
|
||||||
|
# elif defined(__arm__)
|
||||||
|
# define SY__ARCH_ARM 1
|
||||||
|
# elif defined(__aarch64__)
|
||||||
|
# define SY__ARCH_ARM64 1
|
||||||
|
# else
|
||||||
|
# error missing SY__ARCH detection
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
# error no context cracking for this compiler
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(SY__COMPILER_CL)
|
||||||
|
# define SY__COMPILER_CL 0
|
||||||
|
#endif
|
||||||
|
#if !defined(SY__COMPILER_CLANG)
|
||||||
|
# define SY__COMPILER_CLANG 0
|
||||||
|
#endif
|
||||||
|
#if !defined(SY__COMPILER_GCC)
|
||||||
|
# define SY__COMPILER_GCC 0
|
||||||
|
#endif
|
||||||
|
#if !defined(SY__OS_WINDOWS)
|
||||||
|
# define SY__OS_WINDOWS 0
|
||||||
|
#endif
|
||||||
|
#if !defined(SY__OS_LINUX)
|
||||||
|
# define SY__OS_LINUX 0
|
||||||
|
#endif
|
||||||
|
#if !defined(SY__OS_MAC)
|
||||||
|
# define SY__OS_MAC 0
|
||||||
|
#endif
|
||||||
|
#if !defined(SY__ARCH_X64)
|
||||||
|
# define SY__ARCH_X64 0
|
||||||
|
#endif
|
||||||
|
#if !defined(SY__ARCH_X86)
|
||||||
|
# define SY__ARCH_X86 0
|
||||||
|
#endif
|
||||||
|
#if !defined(SY__ARCH_ARM)
|
||||||
|
# define SY__ARCH_ARM 0
|
||||||
|
#endif
|
||||||
|
#if !defined(SY__ARCH_ARM64)
|
||||||
|
# define SY__ARCH_ARM64 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// language
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
# define SY__LANGCXX 1
|
||||||
|
#else
|
||||||
|
# define SY__LANGC 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(SY__LANGCXX)
|
||||||
|
# define SY__LANGCXX 0
|
||||||
|
#endif
|
||||||
|
#if !defined(SY__LANGC)
|
||||||
|
# define SY__LANGC 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// setup pointer size macro
|
||||||
|
#if SY__ARCH_X64 || SY__ARCH_ARM64
|
||||||
|
# define SY__ARCH_ADDRSIZE 64
|
||||||
|
#else
|
||||||
|
# define SY__ARCH_ADDRSIZE 32
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// GLUE(a,b) STRIFY(s)
|
||||||
|
|
||||||
|
#define SY__GLUE__(a,b) a##b
|
||||||
|
#define SY__GLUE_(a,b) SY__GLUE__(a,b)
|
||||||
|
#define SY__GLUE(a,b) SY__GLUE_(a,b)
|
||||||
|
|
||||||
|
#define SY__STRIFY__(s) #s
|
||||||
|
#define SY__STRIFY_(s) SY__STRIFY__(s)
|
||||||
|
#define SY__STRIFY(s) SY__STRIFY_(s)
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// SECTION(<section-name>) <Decl>
|
||||||
|
|
||||||
|
#if SY__COMPILER_CLANG || SY__COMPILER_GCC
|
||||||
|
# if SY__OS_MAC
|
||||||
|
# define SY__SEC_R(N) __attribute__((__section__("__TEXT,"N)))
|
||||||
|
# define SY__SEC_RW(N) __attribute__((__section__("__READ,"N)))
|
||||||
|
# else
|
||||||
|
# define SY__SEC_R(N) __attribute__((__section__(N)))
|
||||||
|
# define SY__SEC_RW(N) __attribute__((__section__(N)))
|
||||||
|
# endif
|
||||||
|
#elif SY__COMPILER_CL
|
||||||
|
# define SY__SEC_R(N) __declspec(allocate(N))
|
||||||
|
# define SY__SEC_RW(N) __declspec(allocate(N))
|
||||||
|
#else
|
||||||
|
# error SY__SEC_R/SY__SEC_RW not defined for this compiler/OS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// for CL users: #pragma section(<section>,read,write)
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// BEFORE_MAIN(name){ <...> }
|
||||||
|
|
||||||
|
#if SY__OS_WINDOWS
|
||||||
|
|
||||||
|
# pragma section(".CRT$XCU", read)
|
||||||
|
|
||||||
|
# if SY__LANG_CXX
|
||||||
|
|
||||||
|
# define SY__BEFORE_MAIN_(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 SY__BEFORE_MAIN_(n) \
|
||||||
|
static void n(void); \
|
||||||
|
__declspec(allocate(".CRT$XCU")) \
|
||||||
|
__pragma(comment(linker,"/include:" #n "__")) \
|
||||||
|
void (*n##__)(void) = n; \
|
||||||
|
static void n(void)
|
||||||
|
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# define SY__BEFORE_MAIN(n) SY__BEFORE_MAIN_(n)
|
||||||
|
|
||||||
|
#elif SY__OS_LINUX
|
||||||
|
|
||||||
|
# define SY__BEFORE_MAIN(n) \
|
||||||
|
__attribute__((constructor)) static void n(void)
|
||||||
|
|
||||||
|
#else
|
||||||
|
# error SY__BEFORE_MAIN missing for this OS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// DO_NOT_ELIMINATE
|
||||||
|
|
||||||
|
#if SY__OS_WINDOWS
|
||||||
|
|
||||||
|
# define SY__DO_NOT_ELIMINATE__S0(N) __pragma(comment(linker,"/include:" #N))
|
||||||
|
# define SY__DO_NOT_ELIMINATE__S1(N) SY__DO_NOT_ELIMINATE__S0(N)
|
||||||
|
# define SY__DO_NOT_ELIMINATE(N) SY__DO_NOT_ELIMINATE__S1(N)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
# define SY__DO_NOT_ELIMINATE(N)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// ALIGN_AS_LIT
|
||||||
|
|
||||||
|
#if SY__COMPILER_CL
|
||||||
|
# define SY__ALIGN_AS_LIT(n) __declspec(align(n))
|
||||||
|
#elif SY__COMPILER_CLANG || SY__COMPILER_GCC
|
||||||
|
# define SY__ALIGN_AS_LIT(n) __attribute__(( __aligned__(n) ))
|
||||||
|
#else
|
||||||
|
# error SY__ALIGN_AS_LIT not defined for this compiler
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// ROUND_UP_POW2
|
||||||
|
|
||||||
|
#define SY__ROUND_UP_POW2(x,p) (((x) + (p) - 1)&~((p) - 1))
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// Types
|
||||||
|
|
||||||
|
#if !defined(SY__TYPES)
|
||||||
|
# include <stdint.h>
|
||||||
|
typedef int8_t SY__S8;
|
||||||
|
typedef int16_t SY__S16;
|
||||||
|
typedef int32_t SY__S32;
|
||||||
|
typedef int64_t SY__S64;
|
||||||
|
typedef uint8_t SY__U8;
|
||||||
|
typedef uint16_t SY__U16;
|
||||||
|
typedef uint32_t SY__U32;
|
||||||
|
typedef uint64_t SY__U64;
|
||||||
|
typedef SY__S8 SY__B8;
|
||||||
|
typedef SY__S16 SY__B16;
|
||||||
|
typedef SY__S32 SY__B32;
|
||||||
|
typedef SY__S64 SY__B64;
|
||||||
|
typedef float SY__F32;
|
||||||
|
typedef double SY__F64;
|
||||||
|
# if SY__ARCH_ADDRSIZE == 32
|
||||||
|
typedef SY__U32 SY__UAddr;
|
||||||
|
typedef SY__S32 SY__SAddr;
|
||||||
|
# elif SY__ARCH_ADDRSIZE == 64
|
||||||
|
typedef SY__U64 SY__UAddr;
|
||||||
|
typedef SY__S64 SY__SAddr;
|
||||||
|
# else
|
||||||
|
# error SY__UAddr and SY__SAddr not defined for this architecture
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
#if SY__OS_LINUX
|
||||||
|
|
||||||
|
extern SyType(SYMBOL_SET_DEFINE) SY__FIRST(SYMBOL_SET_DEFINE);
|
||||||
|
extern SyType(SYMBOL_SET_DEFINE) SY__OPL(SYMBOL_SET_DEFINE);
|
||||||
|
// (these symbols are resolved in the linker script)
|
||||||
|
|
||||||
|
#elif SY__OS_WINDOWS
|
||||||
|
|
||||||
|
#if SY__COMPILER_CL
|
||||||
|
# pragma section(SY__GLUE(SYMBOL_SET_DEFINE,_section),read,write)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(SY__MAIN)
|
||||||
|
|
||||||
|
SyType(SYMBOL_SET_DEFINE) *SY__FIRST(SYMBOL_SET_DEFINE) = 0;
|
||||||
|
SyType(SYMBOL_SET_DEFINE) *SY__OPL(SYMBOL_SET_DEFINE) = 0;
|
||||||
|
|
||||||
|
SY__BEFORE_MAIN(SY__GLUE(SYMBOL_SET_DEFINE,__init)){
|
||||||
|
int size = sizeof(SY__GLUE(SYMBOL_SET_DEFINE,_section)) - 1;
|
||||||
|
sy__section_init(SY__GLUE(SYMBOL_SET_DEFINE,_section), size,
|
||||||
|
(void**)&SY__FIRST(SYMBOL_SET_DEFINE),
|
||||||
|
(void**)&SY__OPL(SYMBOL_SET_DEFINE));
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
extern SyType(SYMBOL_SET_DEFINE) *SY__FIRST(SYMBOL_SET_DEFINE);
|
||||||
|
extern SyType(SYMBOL_SET_DEFINE) *SY__OPL(SYMBOL_SET_DEFINE);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
# error symbol_set.define not implemented for this OS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#undef SYMBOL_SET_DEFINE
|
||||||
|
|
@ -0,0 +1,216 @@
|
||||||
|
#if !defined(SY__H)
|
||||||
|
#define SY__H
|
||||||
|
|
||||||
|
#include "symbol_set.base.h"
|
||||||
|
|
||||||
|
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~ Copy-Pastable Setup ~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
~~ To define a Symbol Set:
|
||||||
|
~~ copy the code below
|
||||||
|
~~ replace ZZZ: to name the symbol set
|
||||||
|
~~ replace Typezz: to set the type of the symbol set
|
||||||
|
~~ replace secz: to name of the data section of the symbol set
|
||||||
|
~~ pick and complete the sections with "..."s
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
|
||||||
|
#define SYMBOL_SET_DEFINE ZZZ
|
||||||
|
#define ZZZ_Type Typezz
|
||||||
|
#define ZZZ_section ".sy.secz"
|
||||||
|
#define ZZZ_marker secz
|
||||||
|
#include "symbol_set.define.h"
|
||||||
|
|
||||||
|
// basic struct def with a name
|
||||||
|
#define ZZZ_DEF(N,...) SyDefine(ZZZ, N) = { ... }
|
||||||
|
|
||||||
|
// def with attached function body
|
||||||
|
// replace funczz: to prefix namespace unique functions
|
||||||
|
// fill ... sections appropriately
|
||||||
|
#define ZZZ_DEF(N,...) \
|
||||||
|
static void funczz##N(void*); \
|
||||||
|
SyDefine(ZZZ, N) = { funczz##N, ... }; \
|
||||||
|
static void funczz##N(void *ptr)
|
||||||
|
|
||||||
|
// nameless def
|
||||||
|
#define ZZZ_DEF(...) SyDefineUnnamed(ZZZ) = { ... }
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
~~~~~~~~~~~~~~~~~~ Loop Boilerplates ~~~~~~~~~~~~~~~~~*/
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
{
|
||||||
|
for (SyEach(ZZZ, zzz_ptr)){
|
||||||
|
zzz_ptr->
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
for (SyEachID(ZZZ, zzz_id)){
|
||||||
|
[zzz_id]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~ User Primitives ~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||||
|
|
||||||
|
#define SyType(S) SY__GLUE(S,_Type)
|
||||||
|
|
||||||
|
#define SyDeclare(S,N) SY__ALIGN_AS_LIT(8) SY__SEC_RW(S##_section) SyType(S) SY__SYMBOL(S,N)
|
||||||
|
#define SyDefine(S,N) SY__DO_NOT_ELIMINATE(SY__SYMBOL(S,N)) SyDeclare(S,N)
|
||||||
|
#define SyDefineUnnamed(S) SyDefine(S,SY__GLUE(unnamed,__COUNTER__))
|
||||||
|
|
||||||
|
#define SyAddress(S,N) (&SY__SYMBOL(S,N))
|
||||||
|
#define SyID(S,N) SyIDFromAddress_Unchecked(S,SyAddress(S,N))
|
||||||
|
#define SyRaw(S,N) (SY__UAddr)(SyAddress(S,N))
|
||||||
|
|
||||||
|
#if SY__OS_WINDOWS
|
||||||
|
# define SyFirst(S) SY__FIRST(S)
|
||||||
|
# define SyOpl(S) SY__OPL(S)
|
||||||
|
#elif SY__OS_LINUX
|
||||||
|
# define SyFirst(S) (&SY__FIRST(S))
|
||||||
|
# define SyOpl(S) (&SY__OPL(S))
|
||||||
|
#else
|
||||||
|
# error missing implementation set locator for this OS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SyStride(S) SY__ROUND_UP_POW2(sizeof(SyType(S)), 8)
|
||||||
|
|
||||||
|
#define SyCount(S) (((SY__U8*)SyOpl(S) - (SY__U8*)SyFirst(S))/SyStride(S))
|
||||||
|
#define SyNext(S,addr) (SyType(S)*)((SY__U8*)addr + SyStride(S))
|
||||||
|
|
||||||
|
#define SyEach(S,var) SyType(S)*var=SyFirst(S); var<SyOpl(S); var=SyNext(S,var)
|
||||||
|
#define SyEachID(S,var) SY__U32 var=1; var<=SyCount(S); var+=1
|
||||||
|
|
||||||
|
#define SyIDFromAddress(S,addr) (SyAddressCheck(S,addr)?SyIDFromAddress_Unchecked(S,addr):0)
|
||||||
|
#define SyAddressFromID(S,id) (SyIDCheck(S,id)?SyAddressFromID_Unchecked(S,id):0)
|
||||||
|
|
||||||
|
#define SyAddressCheck(S,addr) (SyFirst(S) <= (addr) && (addr) <= SyOpl(S))
|
||||||
|
#define SyIDCheck(S,id) (1 <= (id) && (id) <= SyCount(S))
|
||||||
|
|
||||||
|
#define SyIDFromAddress_Unchecked(S,addr) ((SY__U32)(1 + ((SY__U8*)(addr) - (SY__U8*)SyFirst(S))/SyStride(S)))
|
||||||
|
#define SyAddressFromID_Unchecked(S,id) ((SyType(S)*)((SY__U8*)SyFirst(S) + ((id) - 1)*SyStride(S)))
|
||||||
|
|
||||||
|
#define SyIDFromRaw(S,raw) SyIDFromAddress(S,(SyType(S)*)(raw))
|
||||||
|
#define SyIDFromRaw_Unchecked(S,raw) SyIDFromAddress_Unchecked(S,(SyType(S)*)(raw))
|
||||||
|
|
||||||
|
#define SyFlag(S,N) (1llu << (SyID(S,N) - 1))
|
||||||
|
|
||||||
|
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
~~~~~~~~~~~~~~~~~~~ Internal ~~~~~~~~~~~~~~~~~~~~~~*/
|
||||||
|
|
||||||
|
#define SY__SYMBOL(S,N) SY__GLUE(S,SY__GLUE(__,N))
|
||||||
|
|
||||||
|
#define SY__FIRST_(S) SY__GLUE(syfirst__, S##_marker)
|
||||||
|
#define SY__OPL_(S) SY__GLUE(syopl__, S##_marker)
|
||||||
|
|
||||||
|
#define SY__FIRST(S) SY__FIRST_(S)
|
||||||
|
#define SY__OPL(S) SY__OPL_(S)
|
||||||
|
|
||||||
|
#if SY__OS_WINDOWS
|
||||||
|
void sy__section_init(char *name, SY__U32 name_size, void **first_out, void **opl_out);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// I dropped this here so that if you copy paste any of the
|
||||||
|
// above and forget to replace Typezz, you'll get auto-int like
|
||||||
|
// behavior from your error messages.
|
||||||
|
#define Typezz int
|
||||||
|
|
||||||
|
#endif //SY__H
|
||||||
|
|
||||||
|
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~ Function Definitions ~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||||
|
|
||||||
|
#if SY__MAIN && !defined(SY__MAIN_DEFINITIONS)
|
||||||
|
#define SY__MAIN_DEFINITIONS 1
|
||||||
|
|
||||||
|
#if SY__OS_WINDOWS
|
||||||
|
|
||||||
|
#define SY__PE_MSDOS_MAGIC 0x5A4D
|
||||||
|
struct SY__PE_DosHeader{
|
||||||
|
SY__U16 magic;
|
||||||
|
SY__U16 last_page_size;
|
||||||
|
SY__U16 page_count;
|
||||||
|
SY__U16 reloc_count;
|
||||||
|
SY__U16 paragraph_header_size;
|
||||||
|
SY__U16 min_paragraph;
|
||||||
|
SY__U16 max_paragraph;
|
||||||
|
SY__U16 init_ss;
|
||||||
|
SY__U16 init_sp;
|
||||||
|
SY__U16 checksum;
|
||||||
|
SY__U16 init_ip;
|
||||||
|
SY__U16 init_cs;
|
||||||
|
SY__U16 reloc_table_file_off;
|
||||||
|
SY__U16 overlay_number;
|
||||||
|
SY__U16 reserved[4];
|
||||||
|
SY__U16 oem_id;
|
||||||
|
SY__U16 oem_info;
|
||||||
|
SY__U16 reserved2[10];
|
||||||
|
SY__U32 coff_file_offset;
|
||||||
|
};
|
||||||
|
#define SY__PE_SIGNATURE 0x00004550
|
||||||
|
struct SY__PE_CoffHeader{
|
||||||
|
SY__U16 machine_type;
|
||||||
|
SY__U16 section_count;
|
||||||
|
SY__U32 time_stamp;
|
||||||
|
SY__U32 symbol_table_foff;
|
||||||
|
SY__U32 symbol_count;
|
||||||
|
SY__U16 optional_header_size;
|
||||||
|
SY__U16 flags;
|
||||||
|
};
|
||||||
|
struct SY__PE_SectionHeader{
|
||||||
|
SY__U8 name[8];
|
||||||
|
SY__U32 vsize;
|
||||||
|
SY__U32 voff;
|
||||||
|
SY__U32 fsize;
|
||||||
|
SY__U32 foff;
|
||||||
|
SY__U32 relocations_foff;
|
||||||
|
SY__U32 line_numbers_foff;
|
||||||
|
SY__U16 relocation_count;
|
||||||
|
SY__U16 line_number_count;
|
||||||
|
SY__U32 flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
sy__section_init(char *name, SY__U32 name_size,
|
||||||
|
void **first_out, void **opl_out){
|
||||||
|
if (name_size <= 8){
|
||||||
|
extern SY__U8 __ImageBase[];
|
||||||
|
SY__U8 *base = __ImageBase;
|
||||||
|
struct SY__PE_DosHeader *dos = (struct SY__PE_DosHeader*)base;
|
||||||
|
if (dos->magic == SY__PE_MSDOS_MAGIC){
|
||||||
|
SY__U32 *pe_signature = (SY__U32*)(base + dos->coff_file_offset);
|
||||||
|
if (*pe_signature == SY__PE_SIGNATURE){
|
||||||
|
struct SY__PE_CoffHeader *coff = (struct SY__PE_CoffHeader*)(pe_signature + 1);
|
||||||
|
SY__U32 sections_offset = (dos->coff_file_offset + sizeof(*pe_signature) +
|
||||||
|
sizeof(*coff) + coff->optional_header_size);
|
||||||
|
SY__U32 section_count = coff->section_count;
|
||||||
|
struct SY__PE_SectionHeader*
|
||||||
|
section = (struct SY__PE_SectionHeader*)(base + sections_offset);
|
||||||
|
for (SY__U32 i = 0; i < section_count; i += 1, section += 1){
|
||||||
|
SY__B32 match = 1;
|
||||||
|
for (SY__U32 j = 0; j < 8; j += 1){
|
||||||
|
if (name[j] != section->name[j]){
|
||||||
|
match = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (name[j] == 0){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (match){
|
||||||
|
*first_out = base + section->voff;
|
||||||
|
*opl_out = base + section->voff + section->vsize;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* SY__OS_WINDOWS */
|
||||||
|
|
||||||
|
#endif //SY__MAIN_DEFINITIONS
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
#if !defined(SY__INIT_H)
|
||||||
|
#define SY__INIT_H
|
||||||
|
|
||||||
|
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
~~~~~~~~~~~~~~~~~~~ SY Init Definitions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||||
|
|
||||||
|
typedef void SY_InitFunc(void*);
|
||||||
|
typedef struct SY_InitRecord{
|
||||||
|
SY_InitFunc *func;
|
||||||
|
} SY_InitRecord;
|
||||||
|
|
||||||
|
#define SYMBOL_SET_DEFINE SY_INIT
|
||||||
|
#define SY_INIT_Type SY_InitRecord
|
||||||
|
#define SY_INIT_section ".sy.init"
|
||||||
|
#define SY_INIT_marker init
|
||||||
|
#include "mr4th_symbol_set.define.h"
|
||||||
|
|
||||||
|
#define SY_INIT_DEF(N,T) \
|
||||||
|
static void syinit__##N(T*); \
|
||||||
|
SyDefine(SY_INIT, N) = { syinit__##N }; \
|
||||||
|
static void syinit__##N(T*ptr)
|
||||||
|
|
||||||
|
void sy__run_init(void);
|
||||||
|
|
||||||
|
#endif //SY__INIT_H
|
||||||
|
|
||||||
|
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~ Function Definitions ~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||||
|
|
||||||
|
#if SY__MAIN && !defined(SY__INIT_DEFINITIONS)
|
||||||
|
#define SY__INIT_DEFINITIONS 1
|
||||||
|
|
||||||
|
void sy__run_init(void){
|
||||||
|
for (SyEach(SY_INIT, init)){
|
||||||
|
init->func();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //SY__INIT_DEFINITIONS
|
||||||
|
|
||||||
44
todo.txt
44
todo.txt
|
|
@ -3,19 +3,18 @@ Example Writing:
|
||||||
|
|
||||||
[ ] Think up better introductory examples
|
[ ] Think up better introductory examples
|
||||||
[ ] Example of symbol sets with instances that don't need names
|
[ ] Example of symbol sets with instances that don't need names
|
||||||
[ ] Example of more complex data initialization via the hook
|
|
||||||
[ ] Example of symbol set reuse across multiple programs
|
|
||||||
- Metaprogramming without needing input
|
|
||||||
|
|
||||||
|
Practical Use Tips:
|
||||||
Research and Provide Practical Use Tips:
|
|
||||||
|
|
||||||
[ ] See the symbol set in the debugger
|
[ ] See the symbol set in the debugger
|
||||||
[ ] Best ideas for solving serialization systems problem
|
[ ] Best ideas for solving serialization systems problem
|
||||||
[ ] Shader management
|
|
||||||
[ ] IDs for profiler blocks
|
|
||||||
[ ] How does this hold up when multiple DLLs or SOs are involved?
|
[ ] How does this hold up when multiple DLLs or SOs are involved?
|
||||||
|
|
||||||
|
Real Uses:
|
||||||
|
|
||||||
|
[ ] Command Line Options
|
||||||
|
[ ] Shader management
|
||||||
|
[ ] IDs for profiler blocks
|
||||||
|
|
||||||
Vetting:
|
Vetting:
|
||||||
|
|
||||||
|
|
@ -31,40 +30,11 @@ OSs: Win32, Linux, Mac
|
||||||
All combinations of CL, LINK, CLANG work so far so long as the above
|
All combinations of CL, LINK, CLANG work so far so long as the above
|
||||||
options are used.
|
options are used.
|
||||||
}
|
}
|
||||||
Linux{ [ ] GCC CLANG [ ] GCC GCC [ ] CLANG GCC [ ] CLANG CLANG }
|
Linux{ [ ] GCC CLANG [ ] GCC GCC [ ] CLANG GCC [x] CLANG CLANG }
|
||||||
Mac { [ ] CLANG CLANG }
|
Mac { [ ] CLANG CLANG }
|
||||||
|
|
||||||
[ ] Check configurations for link time optimization removal of symbols
|
[ ] Check configurations for link time optimization removal of symbols
|
||||||
|
|
||||||
[ ] Vet __ImageBase trick on Windows linkers
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Development:
|
|
||||||
|
|
||||||
[x] experiment with __ImageBase pseudo variable (linker variable)
|
|
||||||
[ ] Small as possible binary parser for "selfimg" purposes
|
|
||||||
[x] PE
|
|
||||||
[ ] Elf
|
|
||||||
[ ] Macho
|
|
||||||
|
|
||||||
|
|
||||||
"Mark II":
|
|
||||||
|
|
||||||
[ ] Object file editing for improved memory layout & symbol id references
|
|
||||||
[ ] Setup count and base pointer symbols
|
|
||||||
[ ] Learn how to put the symbol data into .data and relink everything
|
|
||||||
[ ] Setup id symbols & editing to give them values
|
|
||||||
[ ] Eliminate the "raw" version of symbols
|
|
||||||
|
|
||||||
[ ] Do I want to maintain a pair of versions one with object file editing
|
|
||||||
and one without?
|
|
||||||
|
|
||||||
Other Upgrade Research:
|
|
||||||
|
|
||||||
[ ] Could Symbol Sets syntax be organized in such a way that it's just a data
|
|
||||||
section and type wrapped in a macro?
|
|
||||||
|
|
||||||
|
|
||||||
Support Tools:
|
Support Tools:
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue