/programs/develop/obj2def/README.md |
---|
0,0 → 1,5 |
# clink |
Very simple (yet?) COFF to COFF linker. Merges several COFF files into one. Only works for dependency-less objects yet (designed exclusively for linking objects into KolibriOS COFF library). |
[Development process](https://www.youtube.com/playlist?list=PLVMOfciBdLI6BPovPgfVZ9bNuwbXetRc9) (in Russian) |
/programs/develop/obj2def/cdict/LICENSE |
---|
0,0 → 1,21 |
MIT License |
Copyright (c) 2020 Magomed Kostoev |
Permission is hereby granted, free of charge, to any person obtaining a copy |
of this software and associated documentation files (the "Software"), to deal |
in the Software without restriction, including without limitation the rights |
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
copies of the Software, and to permit persons to whom the Software is |
furnished to do so, subject to the following conditions: |
The above copyright notice and this permission notice shall be included in all |
copies or substantial portions of the Software. |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
SOFTWARE. |
/programs/develop/obj2def/cdict/README.md |
---|
0,0 → 1,88 |
# CDict - a simple dictionary implementation in C |
## Ready to use! |
It may be used out of the box with key and value of type `CStr` (which is `char *` - zero-terminated string). Once it instantiated in some file using `CDICT_INST` definition: |
```C |
#define CDICT_INST |
#include "cdict.h" |
``` |
It may be then declared just using `#include`: |
```C |
#include "cdict.h" |
int main() { |
CDict_CStr_CStr dict; |
if (!cdict_CStr_CStr_init(&dict)) { |
printf("CDict returned error #%d", dict.error_code); |
return 0; |
} |
cdict_CStr_CStr_add_vv(&dict, "key_a", "value_a", CDICT_REPLACE_EXIST); |
printf("[key_a] = \"%s\"\n", cdict_CStr_CStr_get_v(&dict, "key_a")); |
} |
``` |
## Easy to configure! |
If you want to create a dictionary for other key types you should provide your own keys hashing and comparsion functions, in such case the instantiation of the library will look like this: |
```C |
#define CDICT_INST |
#define CDICT_KEY_T MyType |
#define CDICT_HASH_FN(pkey) my_hash(pkey) |
#define CDICT_CMP_FN(pkey0, pkey1) my_cmp(pkey0, pkey1) |
#include "cdict.h" |
int my_cmp(MyType *pkey0, MyType *pkey1) { |
// Return `whatever_negative` if `key0 < key1`, `0` if `key0 == key1` and `whatever_positive` if `key0 > key1` |
} |
unsigned long my_hash(MyType *key) { |
// Return the hash of the key |
} |
``` |
Then to use the new dictionary you only need to define key type before the header inclusion: |
```C |
#define CDICT_KEY_T MyType |
#include "cdict.h" |
// ... |
CDict_MyType_CStr dict; |
cdict_MyType_CStr_init(&dict); |
// ... |
``` |
If you want to specify the type of values - just define the type: |
```C |
#define CDICT_VAL_T MyValueType |
``` |
And so on. |
## Dependency-free! |
Every single used dependency may be redefined: |
```C |
#define CDICT_ASSERT_FN(x) my_assert(x); |
``` |
## Flexible! |
May define user data to be used in overriden functions (for example - custom allocators): |
```C |
#define CDICT_USER_DATA_T UserData |
#define CDICT_HASHTAB_ITEM_ALLOC_FN(cdict, size) item_alloc(cdict, size) |
#define CDICT_HASHTAB_ITEM_FREE_FN(cdict, ptr) item_free(cdict, ptr) |
#define CDICT_HASHTAB_ALLOC_FN(cdict, size) hashtab_alloc(cdict, size) |
``` |
## Checkout |
[The library](cdict.h). |
/programs/develop/obj2def/cdict/cdict.h |
---|
0,0 → 1,350 |
// Copyright (c) 2020 Magomed Kostoev |
// |
// You may use, distribute and modify this code under the terms of the MIT license. |
// |
// You should have received a copy of the MIT license with this file. If not, please visit |
// https://opensource.org/licenses/MIT or boppan.org/MIT for full license details. |
// cdict.h - simple dictionaty implementation in C. |
// |
// Uses hash table with fixed (but configurable) size. Functions named using given type names: |
// cdict_<CDICT_KEY_T>_<CDICT_VAL_T>_<name>. |
// |
// See configuration below (in public "Input macros" section), also: |
// CDICT_INST: Instantiate the functions if defined. |
// |
// Minimal definitions for declaration: CDICT_KEY_T, CDICT_VAL_T |
// Minimal definitions for instantiation: CDICT_INST, CDICT_KEY_T, CDICT_VAL_T, CDICT_HASH_FN, |
// CDICT_CMP_FN |
// |
// WARNING: All used definitions will be undefined on header exit. |
// |
// Dependencies: |
// <stddef.h> or another source of size_t |
// <stdlib.h> or another source of malloc, and calloc |
// <assert.h> or another source of assert |
// |
// Internal macros for external declarations |
// |
#define CDICT_CAT2_IMPL(x, y) x ## _ ## y |
#define CDICT_CAT2(x, y) CDICT_CAT2_IMPL(x, y) |
/// Creates method name according to CDICT_KEY_T and CDICT_VAL_T |
#define CDICT_FUN(name) CDICT_CAT2(cdict, CDICT_CAT2(CDICT_KEY_T, CDICT_CAT2(CDICT_VAL_T, name))) |
#define cdict_init CDICT_FUN(init) |
#define cdict_init_ud CDICT_FUN(init_ud) |
#define cdict_init_pud CDICT_FUN(init_pud) |
#define cdict_add_pp CDICT_FUN(add_pp) |
#define cdict_add_vv CDICT_FUN(add_vv) |
#define cdict_get_p CDICT_FUN(get_p) |
#define cdict_get_v CDICT_FUN(get_v) |
#define cdict_error_message CDICT_FUN(error_message) |
#define cdict_hash CDICT_FUN(hash) |
#define cdict_keycmp CDICT_FUN(keycmp) |
#define cdict_chain_begin CDICT_FUN(begin) |
#define cdict_chain_next CDICT_FUN(next) |
#define CDictItem CDICT_CAT2(CDictItem, CDICT_CAT2(CDICT_KEY_T, CDICT_VAL_T)) |
#define CDictItem_s CDICT_CAT2(CDictItem_s, CDICT_CAT2(CDICT_KEY_T, CDICT_VAL_T)) |
#define CDict CDICT_CAT2(CDict, CDICT_CAT2(CDICT_KEY_T, CDICT_VAL_T)) |
// |
// Input macros |
// |
/// Type of the dictionary's keys, named type only - used in functions names, default: CStr |
#ifndef CDICT_KEY_T |
typedef char *CStr; |
#define CDICT_CSTR_IS_THERE |
#define CDICT_KEY_T CStr |
#endif |
/// Type of the dictionary's values, named type only - used in functions names, default: CStr |
#ifndef CDICT_VAL_T |
#ifndef CDICT_CSTR_IS_THERE |
typedef char *CStr; |
#endif |
#define CDICT_VAL_T CStr |
#endif |
/// Type of user data |
#ifndef CDICT_USER_DATA_T |
#define CDICT_USER_DATA_T void * |
#endif |
// |
// Public interface |
// |
#define CDICT_NO_CHECK 0 |
#define CDICT_REPLACE_EXIST 1 |
#define CDICT_LEAVE_EXIST 2 |
#define CDICT_ERR_SUCCESS 0 |
#define CDICT_ERR_OUT_OF_MEMORY 1 |
#define CDICT_ERR_THIS_IS_NULL 2 |
#define CDICT_ERR_HASH_TABLE_IS_NULL 3 |
#define CDICT_ERR_PKEY0_IS_NULL 4 |
#define CDICT_ERR_PKEY1_IS_NULL 5 |
#define CDICT_ERR_PKEY_IS_NULL 6 |
#define CDICT_ERR_PVAL_IS_NULL 7 |
typedef struct CDictItem_s { |
struct CDictItem_s *next_collision; |
CDICT_KEY_T key; |
CDICT_VAL_T val; |
} CDictItem; |
typedef struct { |
CDictItem **hash_table; |
CDICT_USER_DATA_T user_data; |
int error_code; |
} CDict; |
/// Initializes dictionary structure |
int cdict_init(CDict *s); |
/// Initializes dictionary structure with non-standard user data |
int cdict_init_ud(CDict *s, CDICT_USER_DATA_T user_data); |
/// Initializes dictionary structure with non-standard user data |
int cdict_init_pud(CDict *s, CDICT_USER_DATA_T *user_data); |
/// Inserts a value by key (receives pointers to val and key) |
CDictItem *cdict_add_pp(CDict *s, CDICT_KEY_T *pkey, CDICT_VAL_T *pval, int if_exists); |
/// Inserts a value by key (receives values of val and key) |
CDictItem *cdict_add_vv(CDict *s, CDICT_KEY_T key, CDICT_VAL_T val, int if_exists); |
/// Gives a value by key (receives a pointer to key) |
CDICT_VAL_T cdict_get_p(CDict *s, CDICT_KEY_T *pkey); |
/// Gives a vaule by key (receives a value of key) |
CDICT_VAL_T cdict_get_v(CDict *s, CDICT_KEY_T key); |
#ifdef CDICT_INST |
// |
// Input macros (instantiation edition) |
// |
/// The value returned on some error |
#ifndef CDICT_VAL_DEFAULT |
#define CDICT_VAL_DEFAULT (CDICT_VAL_T){ 0 } |
#endif |
/// Hashing function for the key type |
#ifndef CDICT_HASH_FN |
#include <string.h> |
#define CDICT_HASH_FN(pkey) strlen(*pkey) ^ (*pkey)[0] |
#else |
#define CDICT_HASH_FN_OVERRIDEN |
#endif |
/// Ammount of pointers to elements in hash table |
#ifndef CDICT_HASHTAB_SZ |
#define CDICT_HASHTAB_SZ 1024 |
#endif |
/// Hash table allocator MUST return zeroed buffer |
#ifndef CDICT_HASHTAB_ALLOC_FN |
#include <stdlib.h> |
#define CDICT_HASHTAB_ALLOC_FN(cdict, size) calloc(1, size) |
#else |
#define CDICT_HASHTAB_ALLOCATORS_OVERRIDDEN |
#endif |
/// New hash table items allocator (should be just a function call) |
#ifndef CDICT_HASHTAB_ITEM_ALLOC_FN |
#include <stdlib.h> |
#define CDICT_HASHTAB_ITEM_ALLOC_FN(cdict, size) malloc(size) |
#define CDICT_HASHTAB_ITEM_FREE_FN(cdict, ptr) free(ptr) |
#else |
#ifndef CDICT_HASHTAB_ITEM_FREE_FN |
#error "CDICT_HASHTAB_ITEM_FREE_FN should be defiend along with CDICT_HASHTAB_ITEM_ALLOC_FN" |
#endif |
#define CDICT_HASHTAB_ITEM_ALLOCATORS_OVERRIDDEN |
#endif |
#ifdef CDICT_HASHTAB_ITEM_ALLOCATORS_OVERRIDDEN |
#error "FUCK!" |
#endif |
/// Replacement for assert from <assert.h> |
#ifndef CDICT_ASSERT_FN |
#include <assert.h> |
#define CDICT_ASSERT_FN(x) if (!x) { printf(__FILE__":%d: Disasserted", __LINE__); } assert(x) |
#endif |
/// Function for comparsion of keys, return should be the same as memcmp |
#ifndef CDICT_CMP_FN |
#include <string.h> |
#define CDICT_CMP_FN(pkey0, pkey1) strcmp(*pkey0, *pkey1) |
#else |
#define CDICT_CMP_FN_OVERRIDDEN |
#endif |
// |
// Internal macros (instantiation edition) |
// |
#define CDICT_ASSERT(x) ({ CDICT_ASSERT_FN(x); x; }) |
// Should write the error code into strucure, but should not rewrite it's already set |
#define CDICT_IF_NULL_SET_ERR_RETURN(x, ec, res) if (x == NULL) { \ |
if (s->error_code == CDICT_ERR_SUCCESS) s->error_code = ec; \ |
return res; \ |
} |
#define CDICT_IF_NULL_RETURN(x, res) if (x == NULL) return res |
// |
// Predeclarations |
// |
#ifdef CDICT_HASHTAB_ITEM_ALLOCATORS_OVERRIDDEN |
void *CDICT_HASHTAB_ITEM_ALLOC_FN(CDict *s, size_t size); |
void CDICT_HASHTAB_ITEM_FREE_FN(CDict *s, CDictItem *ptr); |
#endif |
#ifdef CDICT_HASHTAB_ALLOCATORS_OVERRIDDEN |
void *CDICT_HASHTAB_ALLOC_FN(CDict *s, size_t size); |
#endif |
#ifdef CDICT_HASH_FN_OVERRIDEN |
unsigned long CDICT_HASH_FN(CDICT_KEY_T *pkey); |
#endif |
#ifdef CDICT_CMP_FN_OVERRIDDEN |
int CDICT_CMP_FN(CDICT_KEY_T *pkey0, CDICT_KEY_T *pkey1); |
#endif |
// |
// The code |
// |
static size_t cdict_hash(CDICT_KEY_T *pkey) { |
return CDICT_HASH_FN(CDICT_ASSERT(pkey)) & (CDICT_HASHTAB_SZ - 1); |
} |
static int cdict_keycmp(CDICT_KEY_T *pkey0, CDICT_KEY_T *pkey1) { |
return CDICT_CMP_FN(CDICT_ASSERT(pkey0), CDICT_ASSERT(pkey1)); |
} |
static CDictItem **cdict_chain_begin(CDict *s, CDICT_KEY_T *pkey) { |
CDICT_ASSERT(s); |
size_t hash = cdict_hash(CDICT_ASSERT(pkey)); |
CDICT_IF_NULL_SET_ERR_RETURN(s->hash_table, CDICT_ERR_HASH_TABLE_IS_NULL, NULL); |
return &s->hash_table[hash]; |
} |
static CDictItem **cdict_chain_next(CDictItem **ppit) { |
CDICT_ASSERT(ppit); |
CDICT_ASSERT(*ppit); |
return &(*ppit)->next_collision; |
} |
int cdict_init(CDict *s) { |
return cdict_init_pud(s, NULL); |
} |
int cdict_init_ud(CDict *s, CDICT_USER_DATA_T user_data) { |
return cdict_init_pud(s, &user_data); |
} |
int cdict_init_pud(CDict *s, CDICT_USER_DATA_T *user_data) { |
CDICT_IF_NULL_RETURN(s, 0); |
s->user_data = user_data ? *user_data : (CDICT_USER_DATA_T){ 0 }; |
s->error_code = CDICT_ERR_SUCCESS; |
s->hash_table = CDICT_HASHTAB_ALLOC_FN(s, sizeof(*s->hash_table) * CDICT_HASHTAB_SZ); |
CDICT_IF_NULL_SET_ERR_RETURN(s->hash_table, CDICT_ERR_OUT_OF_MEMORY, 0); |
return 1; |
} |
CDictItem *cdict_add_pp(CDict *s, CDICT_KEY_T *pkey, CDICT_VAL_T *pval, int if_exists) { |
CDICT_IF_NULL_RETURN(s, NULL); |
CDICT_IF_NULL_SET_ERR_RETURN(pkey, CDICT_ERR_PKEY_IS_NULL, NULL); |
CDICT_IF_NULL_SET_ERR_RETURN(pval, CDICT_ERR_PVAL_IS_NULL, NULL); |
CDictItem *next_collision = NULL; |
CDictItem **ppit = cdict_chain_begin(s, pkey); |
CDICT_IF_NULL_RETURN(ppit, NULL); |
while (*ppit) { |
int exists = if_exists == CDICT_NO_CHECK ? 0 : !cdict_keycmp(pkey, &(*ppit)->key); |
if (exists) { |
if (if_exists == CDICT_LEAVE_EXIST) { |
return *ppit; |
} else if (if_exists == CDICT_REPLACE_EXIST) { |
next_collision = (*ppit)->next_collision; |
CDICT_HASHTAB_ITEM_FREE_FN(s, *ppit); |
break; |
} |
} |
ppit = cdict_chain_next(ppit); |
} |
*ppit = CDICT_HASHTAB_ITEM_ALLOC_FN(s, sizeof(**ppit)); |
CDictItem *pit = *ppit; |
pit->key = *pkey; |
pit->val = *pval; |
pit->next_collision = next_collision; |
return pit; |
} |
CDictItem *cdict_add_vv(CDict *s, CDICT_KEY_T key, CDICT_VAL_T val, int if_exists) { |
return cdict_add_pp(s, &key, &val, if_exists); |
} |
CDICT_VAL_T cdict_get_p(CDict *s, CDICT_KEY_T *pkey) { |
CDICT_IF_NULL_RETURN(s, CDICT_VAL_DEFAULT); |
CDICT_IF_NULL_SET_ERR_RETURN(pkey, CDICT_ERR_PKEY_IS_NULL, CDICT_VAL_DEFAULT); |
CDictItem **ppit = cdict_chain_begin(s, pkey); |
CDICT_IF_NULL_RETURN(ppit, CDICT_VAL_DEFAULT); |
while (*ppit) { |
if (!cdict_keycmp(pkey, &(*ppit)->key)) { |
return (*ppit)->val; |
} |
ppit = cdict_chain_next(ppit); |
} |
return CDICT_VAL_DEFAULT; |
} |
CDICT_VAL_T cdict_get_v(CDict *s, CDICT_KEY_T key) { |
return cdict_get_p(s, &key); |
} |
#endif |
#undef CDICT_CAT2_IMPL |
#undef CDICT_CAT2 |
#undef CDICT_FUN |
#undef cdict_init |
#undef cdict_init_ud |
#undef cdict_init_pud |
#undef cdict_add_pp |
#undef cdict_add_vv |
#undef cdict_get_p |
#undef cdict_get_v |
#undef CDICT_KEY_T |
#undef CDICT_VAL_T |
#undef CDICT_USER_DATA_T |
#ifdef CDICT_INST |
#undef CDICT_INST |
#undef CDICT_HASH_FN |
#undef CDICT_HASHTAB_SZ |
#undef CDICT_HASHTAB_ALLOC_FN |
#undef CDICT_HASHTAB_ITEM_ALLOC_FN |
#undef CDICT_HASHTAB_ITEM_FREE_FN |
#undef CDICT_ASSERT_FN |
#undef CDICT_CMP_FN |
#undef CDICT_ASSERT |
#undef CDICT_IF_NULL_RETURN |
#undef CDICT_IF_NULL_SET_ERR_RETURN |
#undef CDICT_HASHTAB_ITEM_ALLOCATORS_OVERRIDDEN |
#undef CDICT_HASHTAB_ALLOCATORS_OVERRIDDEN |
#undef CDICT_HASH_FN_OVERRIDEN |
#undef CDICT_CMP_FN_OVERRIDDEN |
#endif |
/programs/develop/obj2def/cvec/LICENSE |
---|
0,0 → 1,21 |
MIT License |
Copyright (c) 2020 Magomed Kostoev |
Permission is hereby granted, free of charge, to any person obtaining a copy |
of this software and associated documentation files (the "Software"), to deal |
in the Software without restriction, including without limitation the rights |
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
copies of the Software, and to permit persons to whom the Software is |
furnished to do so, subject to the following conditions: |
The above copyright notice and this permission notice shall be included in all |
copies or substantial portions of the Software. |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
SOFTWARE. |
/programs/develop/obj2def/cvec/README.md |
---|
0,0 → 1,88 |
# cvec - partial `std::vector` implementation in C. |
## Partial implementation of `std::vector` |
Member functions table: |
| Status | Name | Function or reason if not implemented | |
| :---: | --- | --- | |
| :heavy_check_mark: | `(constructor)` | `new` | |
| :heavy_check_mark: | `(destructor)` | `free` | |
| :heavy_check_mark: | `operator=` | `assign_other` | |
| :heavy_check_mark: | `assign` | `assign_fill`, `assign_range` | |
| :heavy_minus_sign: | `get_allocator` | No `allocator` objects in the language | |
| :heavy_check_mark: | `at` | `at` | |
| :heavy_check_mark: | `operator[]` | `[]` | |
| :heavy_check_mark: | `front` | `front`, `front_p` | |
| :heavy_check_mark: | `back` | `back`, `back_p` | |
| :heavy_check_mark: | `data` | `data` | |
| :heavy_check_mark: | `begin` | `begin` | |
| :heavy_check_mark: | `cbegin` | `cbegin` | |
| :heavy_check_mark: | `end` | `end` | |
| :heavy_check_mark: | `cend` | `cend` | |
| :heavy_minus_sign: | `rbegin` | No reverse iterators in the language | |
| :heavy_minus_sign: | `crbegin` | No reverse iterators in the language | |
| :heavy_minus_sign: | `rend` | No reverse iterators in the language | |
| :heavy_minus_sign: | `crend` | No reverse iterators in the language | |
| :heavy_check_mark: | `empty` | `empty` | |
| :heavy_check_mark: | `size` | `size` | |
| :heavy_check_mark: | `max_size` | `max_size` | |
| :heavy_check_mark: | `reserve` | `reserve` | |
| :heavy_check_mark: | `capacity` | `capacity` | |
| :heavy_check_mark: | `shrink_to_fit` | `shrink_to_fit` | |
| :heavy_check_mark: | `clear` | `clear` | |
| :heavy_check_mark: | `insert` | `insert`, `insert_it` | |
| :heavy_minus_sign: | `emplace` | I know no way to preserve the original signature | |
| :heavy_check_mark: | `erase` | `erase` | |
| :heavy_check_mark: | `push_back` | `push_back` | |
| :heavy_minus_sign: | `emplace_back` | I know no way to preserve the original signature | |
| :heavy_check_mark: | `pop_back` | `pop_back` | |
| :heavy_check_mark: | `resize` | `resize` | |
| :heavy_minus_sign: | `swap` | Would have n complexity in this implementation | |
## Easy to use |
To use the std::vector implementation for specified type they should be declared as follows: |
```C |
#define CVEC_TYPE TypeOfVectorElement |
#include "cvec.h" |
// ... |
TypeOfVectorElement *vec = cvec_TypeOfVectorElement_new(128); |
cvec_TypeOfVectorElement_push_back(&vec, value); |
``` |
Also somewhere in the project the functinos should be instantiated as follows: |
```C |
#define CVEC_TYPE TypeOfVectorElement |
#define CVEC_INST |
#include "cvec.h" |
``` |
## Allows using of custom allocators. |
```C |
#define CVEC_TYPE pchar |
#define CVEC_INST |
#define CVEC_MALLOC custom_malloc |
#define CVEC_REALLOC custom_realloc |
#define CVEC_FREE custom_free |
#include "cvec.h" |
``` |
## Allows handling of exceptional cases. |
```C |
#define CVEC_TYPE pchar |
#define CVEC_INST |
// Set Out Of Bounds handler |
#define CVEC_OOBH(funcname, vec, index) printf("Out of bounds in %s (vec = %p, i = %d)", funcname, vec, index); abort(); |
#include "cvec.h" |
``` |
## Has no fixed dependencies |
Every function it uses may be overridden. More information about dependencies in [cvec.h](cvec.h). |
/programs/develop/obj2def/cvec/cvec.h |
---|
0,0 → 1,498 |
// Copyright (c) 2015 Evan Teran |
// Copyright (c) 2020 Magomed Kostoev |
// |
// You may use, distribute and modify this code under the terms of the MIT license. |
// |
// You should have received a copy of the MIT license with this file. If not, please visit |
// https://opensource.org/licenses/MIT for full license details. |
// cvec.h - std::vector (ish) implementation in C. Based on https://github.com/eteran/c-vector/. |
// |
// Unlike a real std::vector this one is implemented as a fat array, so metadata is placed inside |
// an allocated buffer itself. |
// |
// Configuration (definitions): |
// CVEC_TYPE: Type of the vector's elements, after instantiation these functions will be visible |
// as cvec_<CVEC_TYPE>_funcname, so no stars and subscripting marks allowed - named |
// types only |
// CVEC_INST: Instantiate the functions if defined |
// CVEC_LOGG: Multiply capacity by CVEC_LOGG each expansion if defined (should be >= 1) |
// CVEC_ASSERT: Replacement for assert from <assert.h> |
// CVEC_MALLOC: Replacement for malloc from <stdlib.h> |
// CVEC_REALLOC: Replacement for realloc from <stdlib.h> |
// CVEC_FREE: Replacement for free from <stdlib.h> |
// CVEC_OOBH: Out-of-bounds handler (gets __func__, vector data address and index of overflow) |
// CVEC_OOBVAL: Default value to return on out of bounds access |
// |
// Minimal definitions for declaration: CVEC_TYPE |
// Minimal definitions for instantiation: CVEC_TYPE, CVEC_INST, CVEC_OOBVAL if the type object |
// can't be represented by 0 value. |
// |
// WARNING: All used definitions will be undefined on header exit. |
// |
// Dependencies: |
// <stddef.h> or another source of size_t and ptrdiff_t |
// <stdint.h> or another source of SIZE_MAX |
// <stdlib.h> or another source of malloc, calloc and realloc |
// <assert.h> or another source of assert |
// |
// Input macros |
// |
#ifndef CVEC_LOGG |
# define CVEC_LOGG 1.5 |
#endif |
#ifndef CVEC_ASSERT |
# define CVEC_ASSERT(x) assert(x) |
#endif |
#ifndef CVEC_MALLOC |
# define CVEC_MALLOC(size) malloc(size) |
#endif |
#ifndef CVEC_REALLOC |
# define CVEC_REALLOC(ptr, size) realloc(ptr, size) |
#endif |
#ifndef CVEC_FREE |
# define CVEC_FREE(size) free(size) |
#endif |
#ifndef CVEC_OOBH |
# define CVEC_OOBH(funcname, vec, index) |
#endif |
#ifndef CVEC_OOBVAL |
# define CVEC_OOBVAL { 0 } |
#endif |
// |
// Internal macros |
// |
#define CVEC_CONCAT2_IMPL(x, y) cvec_ ## x ## _ ## y |
#define CVEC_CONCAT2(x, y) CVEC_CONCAT2_IMPL(x, y) |
/// Creates method name according to CVEC_TYPE |
#define CVEC_FUN(name) CVEC_CONCAT2(CVEC_TYPE, name) |
#define cvec_x_new CVEC_FUN(new) |
#define cvec_x_capacity CVEC_FUN(capacity) |
#define cvec_x_size CVEC_FUN(size) |
#define cvec_x_empty CVEC_FUN(empty) |
#define cvec_x_pop_back CVEC_FUN(pop_back) |
#define cvec_x_erase CVEC_FUN(erase) |
#define cvec_x_free CVEC_FUN(free) |
#define cvec_x_begin CVEC_FUN(begin) |
#define cvec_x_cbegin CVEC_FUN(cbegin) |
#define cvec_x_end CVEC_FUN(end) |
#define cvec_x_cend CVEC_FUN(cend) |
#define cvec_x_push_back CVEC_FUN(push_back) |
#define cvec_x_at CVEC_FUN(at) |
#define cvec_x_reserve CVEC_FUN(reserve) |
#define cvec_x_shrink_to_fit CVEC_FUN(shrink_to_fit) |
#define cvec_x_assign_fill CVEC_FUN(assign_fill) |
#define cvec_x_assign_range CVEC_FUN(assign_range) |
#define cvec_x_assign_other CVEC_FUN(assign_other) |
#define cvec_x_data CVEC_FUN(data) |
#define cvec_x_resize CVEC_FUN(resize) |
#define cvec_x_resize_v CVEC_FUN(resize_v) |
#define cvec_x_clear CVEC_FUN(clear) |
#define cvec_x_front CVEC_FUN(front) |
#define cvec_x_front_p CVEC_FUN(front_p) |
#define cvec_x_back CVEC_FUN(back) |
#define cvec_x_back_p CVEC_FUN(back_p) |
#define cvec_x_max_size CVEC_FUN(max_size) |
#define cvec_x_insert CVEC_FUN(insert) |
#define cvec_x_insert_it CVEC_FUN(insert_it) |
#define cvec_x_grow CVEC_FUN(grow) |
#define cvec_x_set_capacity CVEC_FUN(set_capacity) |
#define cvec_x_set_size CVEC_FUN(set_size) |
// |
// External declarations |
// |
/// Allocates new vector of specified capacity. |
CVEC_TYPE *cvec_x_new(size_t count); |
/// Gets the current capacity of the vector. |
size_t cvec_x_capacity(CVEC_TYPE **vec); |
/// Gets the current size of the vector. |
size_t cvec_x_size(CVEC_TYPE **vec); |
/// Returns non-zero if the vector is empty. |
int cvec_x_empty(CVEC_TYPE **vec); |
/// Removes the last element from the vector. |
void cvec_x_pop_back(CVEC_TYPE **vec); |
/// Removes the element at index i from the vector. |
void cvec_x_erase(CVEC_TYPE **vec, size_t i); |
/// Frees all memory associated with the vector. |
void cvec_x_free(CVEC_TYPE **vec); |
/// Returns an iterator to first element of the vector. |
CVEC_TYPE *cvec_x_begin(CVEC_TYPE **vec); |
/// Returns a const iterator to first element of the vector |
const CVEC_TYPE *cvec_x_cbegin(CVEC_TYPE **vec); |
/// Returns an iterator to one past the last element of the vector. |
CVEC_TYPE *cvec_x_end(CVEC_TYPE **vec); |
/// Returns a const iterator to one past the last element of the vector. |
const CVEC_TYPE *cvec_x_cend(CVEC_TYPE **vec); |
/// Adds an element to the end of the vector. |
void cvec_x_push_back(CVEC_TYPE **vec, CVEC_TYPE value); |
/// Gets element with bounds checking. On out of bounds calls CVEC_OOBH and returns CVEC_OOBVAL. |
CVEC_TYPE cvec_x_at(CVEC_TYPE **vec, size_t i); |
/// Increases the capacity of the vector to a value that's equal to new_cap. |
void cvec_x_reserve(CVEC_TYPE **vec, size_t new_cap); |
/// Requests the removal of unused capacity. |
void cvec_x_shrink_to_fit(CVEC_TYPE **vec); |
/// Replaces the contents with count copies of value value. |
void cvec_x_assign_fill(CVEC_TYPE **vec, size_t count, CVEC_TYPE value); |
/// Replaces the contents with data from range [first, last). |
void cvec_x_assign_range(CVEC_TYPE **vec, CVEC_TYPE *first, CVEC_TYPE *last); |
/// Replaces the contents with contetns of other. |
void cvec_x_assign_other(CVEC_TYPE **vec, CVEC_TYPE **other); |
/// Gives direct access to buffer. |
CVEC_TYPE *cvec_x_data(CVEC_TYPE **vec); |
/// Resizes the container to contain count elements. |
void cvec_x_resize(CVEC_TYPE **vec, size_t new_size); |
/// Resizes the container to contain count elements, initializes new elements by value. |
void cvec_x_resize_v(CVEC_TYPE **vec, size_t new_size, CVEC_TYPE value); |
/// Erases all elements from the container. |
void cvec_x_clear(CVEC_TYPE **vec); |
/// Returns the first element of the vector. |
CVEC_TYPE cvec_x_front(CVEC_TYPE **vec); |
/// Returns a pointer to the first element of the vector. |
CVEC_TYPE *cvec_x_front_p(CVEC_TYPE **vec); |
/// Returns the last element of the vector. |
CVEC_TYPE cvec_x_back(CVEC_TYPE **vec); |
/// Returns a pointer to the last element of the vector. |
CVEC_TYPE *cvec_x_back_p(CVEC_TYPE **vec); |
/// Returns maximal size of the vector. |
size_t cvec_x_max_size(CVEC_TYPE **vec); |
/// Inserts a value into vector by index. |
CVEC_TYPE *cvec_x_insert(CVEC_TYPE **vec, size_t index, CVEC_TYPE value); |
/// Inserts a value into vector by iterator (pointer in vector). |
CVEC_TYPE *cvec_x_insert_it(CVEC_TYPE **vec, CVEC_TYPE *it, CVEC_TYPE value); |
// |
// Function definitions |
// |
#ifdef CVEC_INST |
/// Ensures that the vector is at least <count> elements big. |
static void cvec_x_grow(CVEC_TYPE **vec, size_t count); |
/// Sets the capacity variable of the vector. |
static void cvec_x_set_capacity(CVEC_TYPE **vec, size_t size); |
/// Sets the size variable of the vector. |
static void cvec_x_set_size(CVEC_TYPE **vec, size_t size); |
// |
// Public functions |
// |
CVEC_TYPE *cvec_x_new(size_t count) { |
const size_t cv_sz = count * sizeof(CVEC_TYPE) + sizeof(size_t) * 2; |
size_t *cv_p = CVEC_MALLOC(cv_sz); |
CVEC_ASSERT(cv_p); |
CVEC_TYPE *vec = (void *)(&cv_p[2]); |
cvec_x_set_capacity(&vec, count); |
cvec_x_set_size(&vec, 0); |
return vec; |
} |
size_t cvec_x_capacity(CVEC_TYPE **vec) { |
CVEC_ASSERT(vec); |
return *vec ? ((size_t *)*vec)[-1] : (size_t)0; |
} |
size_t cvec_x_size(CVEC_TYPE **vec) { |
CVEC_ASSERT(vec); |
return *vec ? ((size_t *)*vec)[-2] : (size_t)0; |
} |
int cvec_x_empty(CVEC_TYPE **vec) { |
return cvec_x_size(vec) == 0; |
} |
void cvec_x_pop_back(CVEC_TYPE **vec) { |
cvec_x_set_size(vec, cvec_x_size(vec) - 1); |
} |
void cvec_x_erase(CVEC_TYPE **vec, size_t i) { |
CVEC_ASSERT(vec); |
if (*vec) { |
const size_t cv_sz = cvec_x_size(vec); |
if (i < cv_sz) { |
cvec_x_set_size(vec, cv_sz - 1); |
for (size_t cv_x = i; cv_x < (cv_sz - 1); ++cv_x) { |
(*vec)[cv_x] = (*vec)[cv_x + 1]; |
} |
} |
} |
} |
void cvec_x_free(CVEC_TYPE **vec) { |
CVEC_ASSERT(vec); |
if (*vec) { |
size_t *p1 = &((size_t *)*vec)[-2]; |
CVEC_FREE(p1); |
} |
} |
CVEC_TYPE *cvec_x_begin(CVEC_TYPE **vec) { |
CVEC_ASSERT(vec); |
return *vec; |
} |
const CVEC_TYPE *cvec_x_cbegin(CVEC_TYPE **vec) { |
return cvec_x_begin(vec); |
} |
CVEC_TYPE *cvec_x_end(CVEC_TYPE **vec) { |
CVEC_ASSERT(vec); |
return *vec ? &((*vec)[cvec_x_size(vec)]) : NULL; |
} |
const CVEC_TYPE *cvec_x_cend(CVEC_TYPE **vec) { |
return cvec_x_end(vec); |
} |
void cvec_x_push_back(CVEC_TYPE **vec, CVEC_TYPE value) { |
CVEC_ASSERT(vec); |
size_t cv_cap = cvec_x_capacity(vec); |
if (cv_cap <= cvec_x_size(vec)) { |
cvec_x_grow(vec, cv_cap * CVEC_LOGG + 1); |
} |
(*vec)[cvec_x_size(vec)] = value; |
cvec_x_set_size(vec, cvec_x_size(vec) + 1); |
} |
CVEC_TYPE cvec_x_at(CVEC_TYPE **vec, size_t i) { |
CVEC_ASSERT(vec); |
if (i >= cvec_x_size(vec) || i < 0) { |
CVEC_OOBH(__func__, vec, i); |
CVEC_TYPE ret = CVEC_OOBVAL; |
return ret; |
} |
return (*vec)[i]; |
} |
void cvec_x_reserve(CVEC_TYPE **vec, size_t new_cap) { |
if (new_cap <= cvec_x_capacity(vec)) { |
return; |
} |
cvec_x_grow(vec, new_cap); |
} |
void cvec_x_shrink_to_fit(CVEC_TYPE **vec) { |
if (cvec_x_capacity(vec) > cvec_x_size(vec)) { |
cvec_x_grow(vec, cvec_x_size(vec)); |
} |
} |
void cvec_x_assign_fill(CVEC_TYPE **vec, size_t count, CVEC_TYPE value) { |
CVEC_ASSERT(vec); |
cvec_x_reserve(vec, count); |
cvec_x_set_size(vec, count); // If the buffer was bigger than new_cap, set size ourselves |
for (size_t i = 0; i < count; i++) { |
(*vec)[i] = value; |
} |
} |
void cvec_x_assign_range(CVEC_TYPE **vec, CVEC_TYPE *first, CVEC_TYPE *last) { |
CVEC_ASSERT(vec); |
size_t new_size = ((ptrdiff_t)(last - first)) / sizeof(*first); |
cvec_x_reserve(vec, new_size); |
cvec_x_set_size(vec, new_size); |
size_t i = 0; |
for (CVEC_TYPE *it = first; it < last; it++, i++) { |
(*vec)[i] = *it; |
} |
} |
void cvec_x_assign_other(CVEC_TYPE **vec, CVEC_TYPE **other) { |
cvec_x_assign_range(vec, cvec_x_begin(other), cvec_x_end(other)); |
} |
CVEC_TYPE *cvec_x_data(CVEC_TYPE **vec) { |
CVEC_ASSERT(vec); |
return (*vec); |
} |
void cvec_x_resize(CVEC_TYPE **vec, size_t count) { |
CVEC_TYPE value = { 0 }; |
cvec_x_resize_v(vec, count, value); |
} |
void cvec_x_resize_v(CVEC_TYPE **vec, size_t count, CVEC_TYPE value) { |
CVEC_ASSERT(vec); |
size_t old_size = cvec_x_size(vec); |
cvec_x_set_size(vec, count); |
if (cvec_x_capacity(vec) < count) { |
cvec_x_reserve(vec, count); |
for (CVEC_TYPE *it = (*vec) + old_size; it < cvec_x_end(vec); it++) { |
*it = value; |
} |
} |
} |
void cvec_x_clear(CVEC_TYPE **vec) { |
cvec_x_set_size(vec, 0); |
} |
CVEC_TYPE cvec_x_front(CVEC_TYPE **vec) { |
CVEC_ASSERT(vec); |
return (*vec)[0]; |
} |
CVEC_TYPE *cvec_x_front_p(CVEC_TYPE **vec) { |
CVEC_ASSERT(vec); |
return (*vec); |
} |
CVEC_TYPE cvec_x_back(CVEC_TYPE **vec) { |
return cvec_x_end(vec)[-1]; |
} |
CVEC_TYPE *cvec_x_back_p(CVEC_TYPE **vec) { |
return cvec_x_end(vec) - 1; |
} |
size_t cvec_x_max_size(CVEC_TYPE **vec) { |
return SIZE_MAX / sizeof(**vec); |
} |
CVEC_TYPE *cvec_x_insert(CVEC_TYPE **vec, size_t index, CVEC_TYPE value) { |
CVEC_ASSERT(vec); |
if (index > cvec_x_size(vec) || index < 0) { |
return NULL; // TODO: What? |
} |
size_t new_size = cvec_x_size(vec) + 1; |
cvec_x_reserve(vec, new_size); |
cvec_x_set_size(vec, new_size); |
CVEC_TYPE *ret = *vec + index; |
for (CVEC_TYPE *it = cvec_x_back_p(vec); it > ret; it--) { |
*it = it[-1]; |
} |
*ret = value; |
return ret; |
} |
CVEC_TYPE *cvec_x_insert_it(CVEC_TYPE **vec, CVEC_TYPE *it, CVEC_TYPE value) { |
CVEC_ASSERT(vec); |
size_t index = (it - *vec) / sizeof(**vec); |
return cvec_x_insert(vec, index, value); |
} |
// |
// Private functions |
// |
static void cvec_x_set_capacity(CVEC_TYPE **vec, size_t size) { |
CVEC_ASSERT(vec); |
if (*vec) { |
((size_t *)*vec)[-1] = size; |
} |
} |
static void cvec_x_set_size(CVEC_TYPE **vec, size_t size) { |
CVEC_ASSERT(vec); |
if (*vec) { |
((size_t *)*vec)[-2] = size; |
} |
} |
static void cvec_x_grow(CVEC_TYPE **vec, size_t count) { |
CVEC_ASSERT(vec); |
const size_t cv_sz = count * sizeof(**vec) + sizeof(size_t) * 2; |
size_t *cv_p1 = &((size_t *)*vec)[-2]; |
size_t *cv_p2 = CVEC_REALLOC(cv_p1, (cv_sz)); |
CVEC_ASSERT(cv_p2); |
*vec = (void *)(&cv_p2[2]); |
cvec_x_set_capacity(vec, count); |
} |
#endif |
#undef CVEC_TYPE |
#ifdef CVEC_INST |
# undef CVEC_INST |
# ifdef CVEC_LOGG |
# undef CVEC_LOGG |
# endif |
# ifdef CVEC_OOBH |
# undef CVEC_OOBH |
# endif |
# ifdef CVEC_OOBVAL |
# undef CVEC_OOBVAL |
# endif |
# undef CVEC_ASSERT |
# undef CVEC_MALLOC |
# undef CVEC_REALLOC |
# undef CVEC_FREE |
#endif |
#undef CVEC_CONCAT2_IMPL |
#undef CVEC_CONCAT2 |
#undef CVEC_FUN |
#undef cvec_x_new |
#undef cvec_x_capacity |
#undef cvec_x_size |
#undef cvec_x_empty |
#undef cvec_x_pop_back |
#undef cvec_x_erase |
#undef cvec_x_free |
#undef cvec_x_begin |
#undef cvec_x_cbegin |
#undef cvec_x_end |
#undef cvec_x_cend |
#undef cvec_x_push_back |
#undef cvec_x_at |
#undef cvec_x_reserve |
#undef cvec_x_shrink_to_fit |
#undef cvec_x_assign_fill |
#undef cvec_x_assign_range |
#undef cvec_x_assign_other |
#undef cvec_x_data |
#undef cvec_x_resize |
#undef cvec_x_resize_v |
#undef cvec_x_clear |
#undef cvec_x_front |
#undef cvec_x_front_p |
#undef cvec_x_back |
#undef cvec_x_back_p |
#undef cvec_x_max_size |
#undef cvec_x_insert |
#undef cvec_x_insert_it |
#undef cvec_x_grow |
#undef cvec_x_set_capacity |
#undef cvec_x_set_size |
/programs/develop/obj2def/epep/LICENSE |
---|
0,0 → 1,21 |
MIT License |
Copyright (c) 2020 Magomed Kostoev |
Permission is hereby granted, free of charge, to any person obtaining a copy |
of this software and associated documentation files (the "Software"), to deal |
in the Software without restriction, including without limitation the rights |
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
copies of the Software, and to permit persons to whom the Software is |
furnished to do so, subject to the following conditions: |
The above copyright notice and this permission notice shall be included in all |
copies or substantial portions of the Software. |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
SOFTWARE. |
/programs/develop/obj2def/epep/README.md |
---|
0,0 → 1,26 |
# epep - Embeddable PE Parser |
## Features |
- PE header (including Data Directories as a part Optional Header) |
- Section Headers |
- COFF Symbols |
- COFF Relocations |
- COFF Linenumbers |
- Imports |
- Exports |
- Base relocations (DLL) |
## How to use |
To declare functions from the library include it: |
```C |
#include "epep.h" |
``` |
The functions they shoud be instantiated somewhere in the project like so: |
```C |
#define EPEP_INST |
#include "epep.h" |
``` |
/programs/develop/obj2def/epep/epep.h |
---|
0,0 → 1,1022 |
// Dependencies: |
// <assert.h> or any another source of assert() |
// <stdint.h> or any another source of uint64_t, uint32_t, uint16_t, uint8_t, size_t |
#ifndef EPEP_ASSERT |
#include <assert.h> |
#define EPEP_ASSERT(x) assert(x) |
#endif |
#ifndef EPEP_READER |
#include <stdio.h> |
#define EPEP_READER FILE * |
#define EPEP_READER_GET(preader) getc(*preader) |
#define EPEP_READER_SEEK(preader, offset) fseek(*preader, offset, SEEK_SET) |
#define EPEP_READER_SEEK_END(preader, offset) fseek(*preader, offset, SEEK_END) |
#define EPEP_READER_TELL(preader) ftell(*preader) |
#define EPEP_READER_GET_BLOCK(preader, size, buf) fread(buf, 1, size, *preader); |
#endif |
// |
// Constants |
// |
typedef enum { |
EPEP_INVALID, |
EPEP_IMAGE, |
EPEP_OBJECT, |
} EpepKind; |
typedef enum { |
EPEP_ERR_SUCCESS, |
EPEP_ERR_DATA_DIRECTORY_INDEX_IS_INVALID, |
EPEP_ERR_SECTION_HEADER_INDEX_IS_INVALID, |
EPEP_ERR_SYMBOL_INDEX_IS_INVALID, |
EPEP_ERR_NOT_AN_OBJECT, |
EPEP_ERR_ADDRESS_IS_OUT_OF_SECTION_RAW_DATA, |
EPEP_ERR_OUTPUT_CAPACITY_IS_ZERO, |
EPEP_ERR_OUTPUT_IS_NULL, |
EPEP_ERR_ADDRESS_IS_OUT_OF_ANY_SECTION, |
EPEP_ERR_EXPORT_ADDRESS_TABLE_ENTRY_NAME_NOT_FOUND, |
EPEP_ERR_NO_BASE_RELOCATION_TABLE, |
EPEP_ERR_BASE_RELOCATION_IS_ALREADY_END, |
EPEP_ERR_INVALID_DATA_DIRECTORY_OFFSET, |
EPEP_ERR_INVALID_SECTION_HEADER_OFFSET, |
EPEP_ERR_INVALID_SECTION_DATA_OFFSET, |
EPEP_ERR_INVALID_STRING_TABLE_SIZE_OFFSET, |
EPEP_ERR_INVALID_SYMBOL_OFFSET, |
EPEP_ERR_INVALID_IMPORT_DIRECTORY_OFFSET, |
EPEP_ERR_INVALID_IMPORT_DIRECTORY_NAME_OFFSET, |
EPEP_ERR_INVALID_LOOKUP_OFFSET, |
EPEP_ERR_INVALID_LOOKUP_NAME_OFFSET, |
EPEP_ERR_INVALID_EXPORT_TABLE_OFFSET, |
EPEP_ERR_INVALID_DLL_NAME_OFFSET, |
EPEP_ERR_INVALID_EXPORT_NAME_POINTER_OFFSET, |
EPEP_ERR_INVALID_ORDINAL_TABLE_OFFSET, |
EPEP_ERR_INVALID_EXPORT_NAME_OFFSET, |
EPEP_ERR_INVALID_EXPORT_ADDRESS_OFFSET, |
EPEP_ERR_INVALID_FORWARDER_OFFSET, |
EPEP_ERR_INVALID_BASE_RELOCATION_BLOCK_OFFSET, |
EPEP_ERR_INVALID_NEXT_BASE_RELOCATION_BLOCK_OFFSET, |
EPEP_ERR_INVALID_BASE_RELOCATION_BLOCK_BASE_RELOCATION_OFFSET, |
EPEP_ERR_INVALID_SECTION_RELOCATION_OFFSET, |
EPEP_ERR_INVALID_LINENUMBER_OFFSET, |
} EpepError; |
// |
// Generic |
// |
typedef struct { |
EPEP_READER reader; |
EpepKind kind; |
EpepError error_code; |
size_t file_size; |
size_t signature_offset_offset; |
size_t signature_offset; |
size_t first_data_directory_offset; |
size_t first_section_header_offset; |
size_t export_table_offset; |
size_t import_table_offset; |
size_t base_relocation_table_offset; |
size_t base_relocation_table_end_offset; |
struct { |
uint16_t Machine; |
uint16_t NumberOfSections; |
uint32_t TimeDateStamp; |
uint32_t PointerToSymbolTable; |
uint32_t NumberOfSymbols; |
uint16_t SizeOfOptionalHeader; |
uint16_t Characteristics; |
} coffFileHeader; |
struct { |
// Standard fields |
uint16_t Magic; |
uint8_t MajorLinkerVersion; |
uint8_t MinorLinkerVersion; |
uint32_t SizeOfCode; |
uint32_t SizeOfInitializedData; |
uint32_t SizeOfUninitializedData; |
uint32_t AddressOfEntryPoint; |
uint32_t BaseOfCode; |
uint32_t BaseOfData; // PE32-only |
// Windows-specific fields |
uint64_t ImageBase; |
uint32_t SectionAlignment; |
uint32_t FileAlignment; |
uint16_t MajorOperatingSystemVersion; |
uint16_t MinorOperatingSystemVersion; |
uint16_t MajorImageVersion; |
uint16_t MinorImageVersion; |
uint16_t MajorSubsystemVersion; |
uint16_t MinorSubsystemVersion; |
uint32_t Win32VersionValue; |
uint32_t SizeOfImage; |
uint32_t SizeOfHeaders; |
uint32_t CheckSum; |
uint16_t Subsystem; |
uint16_t DllCharacteristics; |
uint64_t SizeOfStackReserve; |
uint64_t SizeOfStackCommit; |
uint64_t SizeOfHeapReserve; |
uint64_t SizeOfHeapCommit; |
uint32_t LoaderFlags; |
uint32_t NumberOfRvaAndSizes; |
} optionalHeader; |
struct { |
uint32_t ExportFlags; |
uint32_t TimeDateStamp; |
uint16_t MajorVersion; |
uint16_t MinorVersion; |
uint32_t NameRva; |
uint32_t OrdinalBase; |
uint32_t AddressTableEntries; |
uint32_t NumberOfNamePointers; |
uint32_t ExportAddressTableRva; |
uint32_t NamePointerRva; |
uint32_t OrdinalTableRva; |
} export_directory; |
} Epep; |
/// Constructor of the general information container |
int epep_init(Epep *epep, EPEP_READER reader); |
/// Gives file offset corresponding to RVA is any, returns 0 othervice |
int epep_get_file_offset_by_rva(Epep *epep, size_t *offset, size_t addr); |
// |
// Data Directories |
// |
typedef struct { |
uint32_t VirtualAddress; |
uint32_t Size; |
} EpepImageDataDirectory; |
/// Gives Data Directiry by its index |
int epep_get_data_directory_by_index(Epep *epep, EpepImageDataDirectory *idd, size_t index); |
// |
// Sections |
// |
typedef struct { |
char Name[8]; |
uint32_t VirtualSize; |
uint32_t VirtualAddress; |
uint32_t SizeOfRawData; |
uint32_t PointerToRawData; |
uint32_t PointerToRelocations; |
uint32_t PointerToLinenumbers; |
uint16_t NumberOfRelocations; |
uint16_t NumberOfLinenumbers; |
uint32_t Characteristics; |
} EpepSectionHeader; |
/// Gives Section Header by its index |
int epep_get_section_header_by_index(Epep *epep, EpepSectionHeader *sh, size_t index); |
/// Gives section header by RVA |
int epep_get_section_header_by_rva(Epep *epep, EpepSectionHeader *sh, size_t addr); |
/// Gives section contents by Section Header |
int epep_get_section_contents(Epep *epep, EpepSectionHeader *sh, void *buf); |
// |
// COFF Symbols (object file symbols) |
// |
typedef union { |
struct { |
union { |
char ShortName[8]; |
struct { |
uint32_t Zeroes; |
uint32_t Offset; |
}; |
}; |
uint32_t Value; |
uint16_t SectionNumber; |
uint16_t Type; |
uint8_t StorageClass; |
uint8_t NumberOfAuxSymbols; |
} symbol; |
struct { |
uint32_t TagIndex; |
uint32_t TotalSize; |
uint32_t PointerToLinenumber; |
uint32_t PointerToNextFunction; |
uint16_t Unused; |
} auxFunctionDefinition; |
struct { |
uint8_t Unused0[4]; |
uint16_t Linenumber; |
uint8_t Unused1[6]; |
uint32_t PointerToNextFunction; |
uint8_t Unused2[2]; |
} auxBfOrEfSymbol; |
struct { |
uint32_t TagIndex; |
uint32_t Characteristics; |
uint8_t Unused[10]; |
} auxWeakExternal; |
struct { |
char FileName[18]; |
} auxFile; |
struct { |
uint32_t Length; |
uint16_t NumberOfRelocations; |
uint16_t NumberOfLinenumbers; |
uint32_t CheckSum; |
uint16_t Number; |
uint8_t Selection; |
uint8_t Unused[3]; |
} auxSectionDefinition; |
} EpepCoffSymbol; |
/// Gives COFF string table size |
int epep_get_string_table_size(Epep *epep, size_t *size); |
/// Gives COFF string table |
int epep_get_string_table(Epep *epep, char *string_table); |
/// Gives COFF Symbol by its index |
int epep_get_symbol_by_index(Epep *epep, EpepCoffSymbol *sym, size_t index); |
// |
// Imports |
// |
typedef struct { |
uint32_t ImportLookupTableRva; |
uint32_t TimeDateStamp; |
uint32_t ForwarderChain; |
uint32_t NameRva; |
uint32_t ImportAddressTableRva; |
} EpepImportDirectory; |
/// Returns non-zero if import table exists in the file |
int epep_has_import_table(Epep *epep); |
/// Places offset of import table into epep structure |
int epep_read_import_table_offset(Epep *epep); |
/// Gives Import Directory by index |
int epep_get_import_directory_by_index(Epep *epep, EpepImportDirectory *import_directory, size_t index); |
/// Gives name of Import Directory (library) |
int epep_get_import_directory_name_s(Epep *epep, EpepImportDirectory *import_directory, char *name, size_t name_max); |
/// Gives Import Lookup (imported symbol) by import directory and index |
int epep_get_import_directory_lookup_by_index(Epep *epep, EpepImportDirectory *import_directory, size_t *lookup, size_t index); |
/// Gives name of Import Directory Lookup (imported symbol) or nothing if imported by ordinal |
int epep_get_lookup_name_s(Epep *epep, size_t lookup, char *name, size_t name_max); |
// |
// Exports |
// |
typedef union { |
uint32_t ExportRva; |
uint32_t ForwarderRva; |
} EpepExportAddress; |
/// Returns non-zero if export table exists in the file |
int epep_has_export_table(Epep *epep); |
/// Palces offset of export table into epep structrue |
int epep_read_export_table_offset(Epep *epep); |
/// Palces export table into epep structrue |
//! Needs to be called before next export functions |
int epep_read_export_directory(Epep *epep); |
/// Gives name of the DLL |
//! epep_read_export_directory needs to be called before |
int epep_get_dll_name_s(Epep *epep, char *name, size_t name_max); |
/// Gives entry from Export Name Pointer Table by its index |
//! epep_read_export_directory needs to be called before |
int epep_get_export_name_pointer_by_index(Epep *epep, size_t *name_rva, size_t index); |
/// Gives export name by its index in Export Address Table (receives name buffer length) |
//! epep_read_export_directory needs to be called before |
int epep_get_export_name_s_by_index(Epep *epep, char *name, size_t name_max, size_t index); |
/// Gives export address by its index in Export Address Table |
//! epep_read_export_directory needs to be called before |
int epep_get_export_address_by_index(Epep *epep, EpepExportAddress *export_address, size_t index); |
/// Gives forwarder string of Export Address |
//! epep_read_export_directory needs to be called before |
int epep_get_export_address_forwarder_s(Epep *epep, EpepExportAddress *export_address, char *forwarder, size_t forwarder_max); |
/// Returns non-zero if the export address specifies forwarder string |
//! epep_read_export_directory needs to be called before |
int epep_export_address_is_forwarder(Epep *epep, EpepExportAddress *export_address); |
// |
// DLL Base Relocations |
// |
typedef struct { |
size_t offset; |
uint32_t PageRva; |
uint32_t BlockSize; |
uint16_t BaseRelocation[0]; |
} EpepBaseRelocationBlock; |
typedef union { |
struct { |
uint16_t Offset: 12, |
Type: 4; |
}; |
uint16_t u16; |
} EpepBaseRelocation; |
/// Returns non-zero if the file contains Base Relocations |
int epep_has_base_relocation_table(Epep *epep); |
/// Places offset to Base Relocation Table into epep structure |
int epep_read_base_relocation_table_offset(Epep *epep); |
/// Gives first Base Relocation Block |
int epep_get_first_base_relocation_block(Epep *epep, EpepBaseRelocationBlock *brb); |
/// Gives next Base Relocation Block (replaces contents of the given block) |
int epep_get_next_base_relocation_block(Epep *epep, EpepBaseRelocationBlock *it); |
/// Gives Base Relocation by its index in Base Relocation Block |
int epep_get_base_relocation_block_base_relocation_by_index(Epep *epep, EpepBaseRelocationBlock *brb, EpepBaseRelocation *br, size_t index); |
// |
// COFF Relocations |
// |
typedef struct { |
uint32_t VirtualAddress; |
uint32_t SymbolTableIndex; |
uint16_t Type; |
} EpepCoffRelocation; |
int epep_get_section_relocation_by_index(Epep *epep, EpepSectionHeader *sh, EpepCoffRelocation *rel, size_t index); |
// |
// COFF Line Numbers |
// |
typedef struct { |
union { |
uint32_t SymbolTableIndex; |
uint32_t VirtualAddress; |
} Type; |
uint16_t Linenumber; |
} EpepCoffLinenumber; |
int epep_get_section_line_number_by_index(Epep *epep, EpepSectionHeader *sh, EpepCoffLinenumber *ln, size_t index); |
#ifdef EPEP_INST |
// |
// Private functions |
// |
static int epep_seek(Epep *epep, size_t offset) { |
EPEP_READER_SEEK(&epep->reader, offset); |
return 1; |
} |
static int epep_seek_end(Epep *epep, size_t offset) { |
EPEP_READER_SEEK_END(&epep->reader, offset); |
return 1; |
} |
static int epep_read_block(Epep *epep, size_t size, void *block) { |
EPEP_READER_GET_BLOCK(&epep->reader, size, block); |
return 1; |
} |
static int is_pe32(Epep *epep) { |
return epep->optionalHeader.Magic == 0x10b; |
} |
static int is_pe32p(Epep *epep) { |
return epep->optionalHeader.Magic == 0x20b; |
} |
static uint8_t epep_read_u8(Epep *epep) { |
return EPEP_READER_GET(&epep->reader); |
} |
static uint16_t epep_read_u16(Epep *epep) { |
unsigned l = epep_read_u8(epep); |
unsigned h = epep_read_u8(epep); |
return l | (h << 8); |
} |
static uint32_t epep_read_u32(Epep *epep) { |
unsigned b0 = epep_read_u8(epep); |
unsigned b1 = epep_read_u8(epep); |
unsigned b2 = epep_read_u8(epep); |
unsigned b3 = epep_read_u8(epep); |
return b0 | (b1 << 8) | (b2 << 16) | (b3 << 24); |
} |
static uint64_t epep_read_u64(Epep *epep) { |
uint64_t res = 0; |
for (unsigned i = 0; i < 64; i += 8) { |
res |= epep_read_u8(epep) << i; |
} |
return res; |
} |
static uint64_t epep_read_ptr(Epep *epep) { |
return is_pe32(epep) ? epep_read_u32(epep) : epep_read_u64(epep); |
} |
static int epep_valid_offset(Epep *epep, size_t offset, size_t size) { |
return (offset + size) <= epep->file_size; |
} |
// |
// Generic |
// |
int epep_init(Epep *epep, EPEP_READER reader) { |
*epep = (Epep){ 0 }; |
epep->kind = EPEP_IMAGE; |
epep->reader = reader; |
epep_seek_end(epep, 0); |
epep->file_size = EPEP_READER_TELL(&epep->reader); |
epep_seek(epep, 0); |
epep->error_code = EPEP_ERR_SUCCESS; |
epep->signature_offset_offset = 0x3c; |
epep_seek(epep, epep->signature_offset_offset); |
epep->signature_offset = epep_read_u32(epep); |
epep_seek(epep, epep->signature_offset); |
char signature_buf[4]; |
signature_buf[0] = epep_read_u8(epep); |
signature_buf[1] = epep_read_u8(epep); |
signature_buf[2] = epep_read_u8(epep); |
signature_buf[3] = epep_read_u8(epep); |
if (signature_buf[0] != 'P' || signature_buf[1] != 'E' || |
signature_buf[2] != '\0' || signature_buf[3] != '\0') { |
epep->kind = EPEP_OBJECT; |
epep_seek(epep, 0); |
} |
epep->coffFileHeader.Machine = epep_read_u16(epep); |
epep->coffFileHeader.NumberOfSections = epep_read_u16(epep); |
epep->coffFileHeader.TimeDateStamp = epep_read_u32(epep); |
epep->coffFileHeader.PointerToSymbolTable = epep_read_u32(epep); |
epep->coffFileHeader.NumberOfSymbols = epep_read_u32(epep); |
epep->coffFileHeader.SizeOfOptionalHeader = epep_read_u16(epep); |
epep->coffFileHeader.Characteristics = epep_read_u16(epep); |
if (epep->coffFileHeader.SizeOfOptionalHeader != 0) { |
// Standard fields |
epep->optionalHeader.Magic = epep_read_u16(epep); |
epep->optionalHeader.MajorLinkerVersion = epep_read_u8(epep); |
epep->optionalHeader.MinorLinkerVersion = epep_read_u8(epep); |
epep->optionalHeader.SizeOfCode = epep_read_u32(epep); |
epep->optionalHeader.SizeOfInitializedData = epep_read_u32(epep); |
epep->optionalHeader.SizeOfUninitializedData = epep_read_u32(epep); |
epep->optionalHeader.AddressOfEntryPoint = epep_read_u32(epep); |
epep->optionalHeader.BaseOfCode = epep_read_u32(epep); |
if (is_pe32(epep)) { |
epep->optionalHeader.BaseOfData = epep_read_u32(epep); |
} |
// Windows-specific fields |
epep->optionalHeader.ImageBase = epep_read_ptr(epep); |
epep->optionalHeader.SectionAlignment = epep_read_u32(epep); |
epep->optionalHeader.FileAlignment = epep_read_u32(epep); |
epep->optionalHeader.MajorOperatingSystemVersion = epep_read_u16(epep); |
epep->optionalHeader.MinorOperatingSystemVersion = epep_read_u16(epep); |
epep->optionalHeader.MajorImageVersion = epep_read_u16(epep); |
epep->optionalHeader.MinorImageVersion = epep_read_u16(epep); |
epep->optionalHeader.MajorSubsystemVersion = epep_read_u16(epep); |
epep->optionalHeader.Win32VersionValue = epep_read_u32(epep); |
epep->optionalHeader.MinorSubsystemVersion = epep_read_u16(epep); |
epep->optionalHeader.SizeOfImage = epep_read_u32(epep); |
epep->optionalHeader.SizeOfHeaders = epep_read_u32(epep); |
epep->optionalHeader.CheckSum = epep_read_u32(epep); |
epep->optionalHeader.Subsystem = epep_read_u16(epep); |
epep->optionalHeader.DllCharacteristics = epep_read_u16(epep); |
epep->optionalHeader.SizeOfStackReserve = epep_read_ptr(epep); |
epep->optionalHeader.SizeOfStackCommit = epep_read_ptr(epep); |
epep->optionalHeader.SizeOfHeapReserve = epep_read_ptr(epep); |
epep->optionalHeader.SizeOfHeapCommit = epep_read_ptr(epep); |
epep->optionalHeader.LoaderFlags = epep_read_u32(epep); |
epep->optionalHeader.NumberOfRvaAndSizes = epep_read_u32(epep); |
epep->first_data_directory_offset = EPEP_READER_TELL(&epep->reader); |
} |
epep->first_section_header_offset = EPEP_READER_TELL(&epep->reader); |
if (epep->coffFileHeader.SizeOfOptionalHeader != 0) { |
epep->first_section_header_offset += epep->optionalHeader.NumberOfRvaAndSizes * sizeof(EpepImageDataDirectory); |
} |
return 1; |
} |
int epep_get_file_offset_by_rva(Epep *epep, size_t *offset, size_t addr) { |
EpepSectionHeader sh = { 0 }; |
if (!epep_get_section_header_by_rva(epep, &sh, addr)) { |
return 0; |
} |
size_t diff = addr - sh.VirtualAddress; |
if (diff >= sh.SizeOfRawData) { |
epep->error_code = EPEP_ERR_ADDRESS_IS_OUT_OF_SECTION_RAW_DATA; |
return 0; |
} |
*offset = sh.PointerToRawData + diff; |
return 1; |
} |
// |
// Data Directories |
// |
int epep_get_data_directory_by_index(Epep *epep, EpepImageDataDirectory *idd, size_t index) { |
if (index >= epep->optionalHeader.NumberOfRvaAndSizes) { |
epep->error_code = EPEP_ERR_DATA_DIRECTORY_INDEX_IS_INVALID; |
return 0; |
} |
size_t offset = epep->first_data_directory_offset + sizeof(EpepImageDataDirectory) * index; |
if (!epep_valid_offset(epep, offset, sizeof(EpepImageDataDirectory))) { |
epep->error_code = EPEP_ERR_INVALID_DATA_DIRECTORY_OFFSET; |
return 0; |
} |
epep_seek(epep, offset); |
idd->VirtualAddress = epep_read_u32(epep); |
idd->Size = epep_read_u32(epep); |
return 1; |
} |
// |
// Sections |
// |
int epep_get_section_header_by_index(Epep *epep, EpepSectionHeader *sh, size_t index) { |
if (index >= epep->coffFileHeader.NumberOfSections) { |
epep->error_code = EPEP_ERR_SECTION_HEADER_INDEX_IS_INVALID; |
return 0; |
} |
size_t offset = epep->first_section_header_offset + sizeof(EpepSectionHeader) * index; |
if (!epep_valid_offset(epep, offset, sizeof(EpepSectionHeader))) { |
epep->error_code = EPEP_ERR_INVALID_SECTION_HEADER_OFFSET; |
return 0; |
} |
epep_seek(epep, offset); |
for (int i = 0; i < 8; i++) { |
sh->Name[i] = epep_read_u8(epep); |
} |
sh->VirtualSize = epep_read_u32(epep); |
sh->VirtualAddress = epep_read_u32(epep); |
sh->SizeOfRawData = epep_read_u32(epep); |
sh->PointerToRawData = epep_read_u32(epep); |
sh->PointerToRelocations = epep_read_u32(epep); |
sh->PointerToLinenumbers = epep_read_u32(epep); |
sh->NumberOfRelocations = epep_read_u16(epep); |
sh->NumberOfLinenumbers = epep_read_u16(epep); |
sh->Characteristics = epep_read_u32(epep); |
return 1; |
} |
int epep_get_section_header_by_rva(Epep *epep, EpepSectionHeader *sh, size_t addr) { |
EpepSectionHeader sh0 = { 0 }; |
for (size_t i = 0; i < epep->coffFileHeader.NumberOfSections; i++) { |
epep_get_section_header_by_index(epep, &sh0, i); |
if (addr >= sh0.VirtualAddress && addr < (sh0.VirtualAddress + sh0.VirtualSize)) { |
*sh = sh0; |
return 1; |
} |
} |
epep->error_code = EPEP_ERR_ADDRESS_IS_OUT_OF_ANY_SECTION; |
return 0; |
} |
int epep_get_section_contents(Epep *epep, EpepSectionHeader *sh, void *buf) { |
size_t offset = sh->PointerToRawData; |
size_t size_of_raw_data = sh->SizeOfRawData; |
if (!epep_valid_offset(epep, offset, size_of_raw_data)) { |
epep->error_code = EPEP_ERR_INVALID_SECTION_DATA_OFFSET; |
return 0; |
} |
epep_seek(epep, offset); |
epep_read_block(epep, size_of_raw_data, buf); |
return 1; |
} |
// |
// COFF Symbols |
// |
int epep_get_string_table_size(Epep *epep, size_t *size) { |
size_t offset = epep->coffFileHeader.PointerToSymbolTable + 18 * epep->coffFileHeader.NumberOfSymbols; |
if (!epep_valid_offset(epep, offset, sizeof(uint32_t))) { |
epep->error_code = EPEP_ERR_INVALID_STRING_TABLE_SIZE_OFFSET; |
return 0; |
} |
epep_seek(epep, offset); |
*size = epep_read_u32(epep); |
return 1; |
} |
int epep_get_string_table(Epep *epep, char *string_table) { |
size_t size = 0; |
if (!epep_get_string_table_size(epep, &size)) { |
return 0; |
} |
// A COFF strings table starts with its size |
*string_table++ = (size & 0x000000ff) >> 0; |
*string_table++ = (size & 0x0000ff00) >> 8; |
*string_table++ = (size & 0x00ff0000) >> 16; |
*string_table++ = (size & 0xff000000) >> 24; |
epep_read_block(epep, size - 4, string_table); |
return 1; |
} |
int epep_get_symbol_by_index(Epep *epep, EpepCoffSymbol *sym, size_t index) { |
if (epep->kind != EPEP_OBJECT) { |
epep->error_code = EPEP_ERR_NOT_AN_OBJECT; |
return 0; |
} |
if (index >= epep->coffFileHeader.NumberOfSymbols) { |
epep->error_code = EPEP_ERR_SYMBOL_INDEX_IS_INVALID; |
return 0; |
} |
size_t offset = epep->coffFileHeader.PointerToSymbolTable + 18 * index; |
if (!epep_valid_offset(epep, offset, 18)) { |
epep->error_code = EPEP_ERR_INVALID_SYMBOL_OFFSET; |
return 0; |
} |
epep_seek(epep, offset); |
for (size_t i = 0; i < 18; i++) { |
sym->auxFile.FileName[i] = epep_read_u8(epep); |
} |
return 1; |
} |
// |
// Imports |
// |
int epep_has_import_table(Epep *epep) { |
if (epep->kind != EPEP_IMAGE) { |
return 0; |
} |
EpepImageDataDirectory idd = { 0 }; |
if (!epep_get_data_directory_by_index(epep, &idd, 1)) { |
return 0; |
} |
return idd.VirtualAddress; |
} |
int epep_read_import_table_offset(Epep *epep) { |
EpepImageDataDirectory import_table_dd = { 0 }; |
if (!epep_get_data_directory_by_index(epep, &import_table_dd, 1)) { |
return 0; |
} |
if (!epep_get_file_offset_by_rva(epep, &epep->import_table_offset, import_table_dd.VirtualAddress)) { |
return 0; |
} |
return 1; |
} |
int epep_get_import_directory_by_index(Epep *epep, EpepImportDirectory *import_directory, size_t index) { |
if (epep->import_table_offset == 0) { |
if (!epep_read_import_table_offset(epep)) { |
return 0; |
} |
} |
size_t offset = epep->import_table_offset + index * sizeof(*import_directory); |
if (!epep_valid_offset(epep, offset, sizeof(*import_directory))) { |
epep->error_code = EPEP_ERR_INVALID_IMPORT_DIRECTORY_OFFSET; |
return 0; |
} |
epep_seek(epep, offset); |
epep_read_block(epep, sizeof(*import_directory), import_directory); |
return 1; |
} |
int epep_get_import_directory_name_s(Epep *epep, EpepImportDirectory *import_directory, char *name, size_t name_max) { |
size_t name_rva = import_directory->NameRva; |
size_t name_offset = 0; |
if (!epep_get_file_offset_by_rva(epep, &name_offset, name_rva)) { |
return 0; |
} |
if (!epep_valid_offset(epep, name_offset, 0)) { |
epep->error_code = EPEP_ERR_INVALID_IMPORT_DIRECTORY_NAME_OFFSET; |
return 0; |
} |
epep_seek(epep, name_offset); |
epep_read_block(epep, name_max, name); |
return 1; |
} |
int epep_get_import_directory_lookup_by_index(Epep *epep, EpepImportDirectory *import_directory, size_t *lookup, size_t index) { |
size_t first_lookup_offset = 0; |
if (!epep_get_file_offset_by_rva(epep, &first_lookup_offset, import_directory->ImportLookupTableRva)) { |
return 0; |
} |
size_t size_of_lookup = is_pe32(epep) ? 4 : 8; |
size_t lookup_offset = first_lookup_offset + size_of_lookup * index; |
if (!epep_valid_offset(epep, lookup_offset, size_of_lookup)) { |
epep->error_code = EPEP_ERR_INVALID_LOOKUP_OFFSET; |
return 0; |
} |
epep_seek(epep, lookup_offset); |
epep_read_block(epep, size_of_lookup, lookup); |
return 1; |
} |
int epep_get_lookup_name_s(Epep *epep, size_t lookup, char *name, size_t name_max) { |
if (name_max == 0) { |
epep->error_code = EPEP_ERR_OUTPUT_CAPACITY_IS_ZERO; |
return 0; |
} |
if (name == NULL) { |
epep->error_code = EPEP_ERR_OUTPUT_IS_NULL; |
return 0; |
} |
uint64_t mask = is_pe32(epep) ? 0x80000000 : 0x8000000000000000; |
if (lookup & mask) { |
name[0] = '\0'; |
return 1; |
} |
size_t name_rva = lookup; |
size_t name_offset = 0; |
if (!epep_get_file_offset_by_rva(epep, &name_offset, name_rva)) { |
return 0; |
} |
// skip 2 bytes (Name Table :: Hint) |
name_offset += 2; |
if (!epep_valid_offset(epep, name_offset, 0)) { |
epep->error_code = EPEP_ERR_INVALID_LOOKUP_NAME_OFFSET; |
return 0; |
} |
epep_seek(epep, name_offset); |
epep_read_block(epep, name_max, name); |
return 1; |
} |
// |
// Exports |
// |
int epep_has_export_table(Epep *epep) { |
if (epep->kind != EPEP_IMAGE) { |
return 0; |
} |
EpepImageDataDirectory idd = { 0 }; |
if (!epep_get_data_directory_by_index(epep, &idd, 0)) { |
return 0; |
} |
return idd.VirtualAddress; |
} |
int epep_read_export_table_offset(Epep *epep) { |
EpepImageDataDirectory export_table_dd = { 0 }; |
if (!epep_get_data_directory_by_index(epep, &export_table_dd, 0)) { |
return 0; |
} |
if (!epep_get_file_offset_by_rva(epep, &epep->export_table_offset, export_table_dd.VirtualAddress)) { |
return 0; |
} |
return 1; |
} |
int epep_read_export_directory(Epep *epep) { |
if (epep->export_table_offset == 0) { |
if (!epep_read_export_table_offset(epep)) { |
return 0; |
} |
} |
if (!epep_valid_offset(epep, epep->export_table_offset, sizeof(epep->export_directory))) { |
epep->error_code = EPEP_ERR_INVALID_EXPORT_TABLE_OFFSET; |
return 0; |
} |
epep_seek(epep, epep->export_table_offset); |
epep_read_block(epep, sizeof(epep->export_directory), &epep->export_directory); |
return 1; |
} |
int epep_get_dll_name_s(Epep *epep, char *name, size_t name_max) { |
size_t offset = 0; |
if (!epep_get_file_offset_by_rva(epep, &offset, epep->export_directory.NameRva)) { |
return 0; |
} |
if (!epep_valid_offset(epep, offset, 0)) { |
epep->error_code = EPEP_ERR_INVALID_DLL_NAME_OFFSET; |
return 0; |
} |
epep_seek(epep, offset); |
epep_read_block(epep, name_max, name); |
return 1; |
} |
int epep_get_export_name_pointer_by_index(Epep *epep, size_t *name_rva, size_t index) { |
size_t name_pointer_table_rva = epep->export_directory.NamePointerRva; |
size_t name_pointer_table_offset = 0; |
if (!epep_get_file_offset_by_rva(epep, &name_pointer_table_offset, name_pointer_table_rva)) { |
return 0; |
} |
size_t offset = name_pointer_table_offset + sizeof(uint32_t) * index; |
if (!epep_valid_offset(epep, offset, sizeof(uint32_t))) { |
epep->error_code = EPEP_ERR_INVALID_EXPORT_NAME_POINTER_OFFSET; |
return 0; |
} |
epep_seek(epep, offset); |
*name_rva = epep_read_u32(epep); |
return 1; |
} |
int epep_get_export_name_s_by_index(Epep *epep, char *name, size_t name_max, size_t index) { |
size_t ordinal_table_offset = 0; |
if (!epep_get_file_offset_by_rva(epep, &ordinal_table_offset, epep->export_directory.OrdinalTableRva)) { |
return 0; |
} |
if (!epep_valid_offset(epep, ordinal_table_offset, 0)) { |
epep->error_code = EPEP_ERR_INVALID_ORDINAL_TABLE_OFFSET; |
return 0; |
} |
epep_seek(epep, ordinal_table_offset); |
for (size_t i = 0; i < epep->export_directory.NumberOfNamePointers; i++) { |
uint16_t ordinal = epep_read_u16(epep); |
if (ordinal == index) { // SPEC_VIOL: Why should not epep->export_directory.OrdinalBase be substracted? |
size_t name_rva = 0; |
if (!epep_get_export_name_pointer_by_index(epep, &name_rva, i)) { |
return 0; |
} |
size_t name_offset = 0; |
if (!epep_get_file_offset_by_rva(epep, &name_offset, name_rva)) { |
return 0; |
} |
if (!epep_valid_offset(epep, name_offset, 0)) { |
epep->error_code = EPEP_ERR_INVALID_EXPORT_NAME_OFFSET; |
return 0; |
} |
epep_seek(epep, name_offset); |
epep_read_block(epep, name_max, name); |
return 1; |
} |
} |
epep->error_code = EPEP_ERR_EXPORT_ADDRESS_TABLE_ENTRY_NAME_NOT_FOUND; |
return 0; |
} |
int epep_get_export_address_by_index(Epep *epep, EpepExportAddress *export_address, size_t index) { |
size_t export_address_table_offset = 0; |
if (!epep_get_file_offset_by_rva(epep, &export_address_table_offset, epep->export_directory.ExportAddressTableRva)) { |
return 0; |
} |
EPEP_ASSERT(sizeof(EpepExportAddress) == sizeof(uint32_t)); |
size_t offset = export_address_table_offset + sizeof(EpepExportAddress) * index; |
if (!epep_valid_offset(epep, offset, sizeof(*export_address))) { |
epep->error_code = EPEP_ERR_INVALID_EXPORT_ADDRESS_OFFSET; |
return 0; |
} |
epep_seek(epep, offset); |
epep_read_block(epep, sizeof(*export_address), export_address); |
return 1; |
} |
int epep_get_export_address_forwarder_s(Epep *epep, EpepExportAddress *export_address, char *forwarder, size_t forwarder_max) { |
size_t forwarder_offset = 0; |
if (!epep_get_file_offset_by_rva(epep, &forwarder_offset, export_address->ForwarderRva)) { |
return 0; |
} |
if (!epep_valid_offset(epep, forwarder_offset, 0)) { |
epep->error_code = EPEP_ERR_INVALID_FORWARDER_OFFSET; |
return 0; |
} |
epep_seek(epep, forwarder_offset); |
epep_read_block(epep, forwarder_max, forwarder); |
return 1; |
} |
int epep_export_address_is_forwarder(Epep *epep, EpepExportAddress *export_address) { |
EpepImageDataDirectory edd = { 0 }; |
if (!epep_get_data_directory_by_index(epep, &edd, 0)) { |
return 0; |
} |
if (export_address->ForwarderRva >= edd.VirtualAddress && export_address->ForwarderRva < edd.VirtualAddress + edd.Size) { |
return 1; |
} |
return 0; |
} |
// |
// DLL Base Relocaions |
// |
int epep_has_base_relocation_table(Epep *epep) { |
EpepImageDataDirectory brtdd = { 0 }; |
if (!epep_get_data_directory_by_index(epep, &brtdd, 5)) { |
return 0; |
} |
if (brtdd.VirtualAddress == 0) { |
return 0; |
} |
return 1; |
} |
int epep_read_base_relocation_table_offset(Epep *epep) { |
EpepImageDataDirectory brtdd = { 0 }; |
if (!epep_get_data_directory_by_index(epep, &brtdd, 5)) { |
return 0; |
} |
if (!epep_get_file_offset_by_rva(epep, &epep->base_relocation_table_offset, brtdd.VirtualAddress)) { |
return 0; |
} |
epep->base_relocation_table_end_offset = epep->base_relocation_table_offset + brtdd.Size; |
return 1; |
} |
int epep_get_first_base_relocation_block(Epep *epep, EpepBaseRelocationBlock *brb) { |
if (epep->base_relocation_table_offset == 0) { |
if (!epep_read_base_relocation_table_offset(epep)) { |
return 0; |
} |
} |
if (epep->base_relocation_table_offset == 0) { |
epep->error_code = EPEP_ERR_NO_BASE_RELOCATION_TABLE; |
return 0; |
} |
if (!epep_valid_offset(epep, epep->base_relocation_table_offset, 0)) { |
epep->error_code = EPEP_ERR_INVALID_BASE_RELOCATION_BLOCK_OFFSET; |
return 0; |
} |
if (!epep_seek(epep, epep->base_relocation_table_offset)) { |
return 0; |
} |
brb->offset = epep->base_relocation_table_offset; |
brb->PageRva = epep_read_u32(epep); |
brb->BlockSize = epep_read_u32(epep); |
return 1; |
} |
int epep_get_next_base_relocation_block(Epep *epep, EpepBaseRelocationBlock *it) { |
if (it->offset == 0) { |
epep->error_code = EPEP_ERR_BASE_RELOCATION_IS_ALREADY_END; |
return 0; |
} |
it->offset = it->offset + it->BlockSize; |
if (it->offset >= epep->base_relocation_table_end_offset) { |
*it = (EpepBaseRelocationBlock){ 0 }; |
return 1; |
} |
if (!epep_valid_offset(epep, it->offset, 0)) { |
epep->error_code = EPEP_ERR_INVALID_NEXT_BASE_RELOCATION_BLOCK_OFFSET; |
return 0; |
} |
if (!epep_seek(epep, it->offset)) { |
return 0; |
} |
it->PageRva = epep_read_u32(epep); |
it->BlockSize = epep_read_u32(epep); |
return 1; |
} |
int epep_get_base_relocation_block_base_relocation_by_index(Epep *epep, EpepBaseRelocationBlock *brb, EpepBaseRelocation *br, size_t index) { |
size_t offset = brb->offset + 8 + sizeof(EpepBaseRelocation) * index; |
if (!epep_valid_offset(epep, offset, sizeof(EpepBaseRelocation))) { |
epep->error_code = EPEP_ERR_INVALID_BASE_RELOCATION_BLOCK_BASE_RELOCATION_OFFSET; |
return 0; |
} |
if (!epep_seek(epep, offset)) { |
return 0; |
} |
br->u16 = epep_read_u16(epep); |
return 1; |
} |
// |
// COFF Relocations |
// |
int epep_get_section_relocation_by_index(Epep *epep, EpepSectionHeader *sh, EpepCoffRelocation *rel, size_t index) { |
size_t offset = sh->PointerToRelocations + 10 * index; |
if (!epep_valid_offset(epep, offset, 10)) { |
epep->error_code = EPEP_ERR_INVALID_SECTION_RELOCATION_OFFSET; |
return 0; |
} |
epep_seek(epep, offset); |
epep_read_block(epep, 10, rel); |
return 1; |
} |
// |
// COFF Line Numbers |
// |
int epep_get_section_line_number_by_index(Epep *epep, EpepSectionHeader *sh, EpepCoffLinenumber *ln, size_t index) { |
size_t offset = sh->PointerToLinenumbers + 6 * index; |
if (!epep_valid_offset(epep, offset, 6)) { |
epep->error_code = EPEP_ERR_INVALID_LINENUMBER_OFFSET; |
return 0; |
} |
epep_seek(epep, offset); |
epep_read_block(epep, 6, ln); |
return 1; |
} |
#endif // EPEP_INST |
/programs/develop/obj2def/main.c |
---|
0,0 → 1,265 |
#include <stdarg.h> |
#include <stddef.h> |
#include <stdlib.h> |
#include <stdio.h> |
#include <stdint.h> |
#include <assert.h> |
#include <string.h> |
#define EPEP_INST |
#include "epep/epep.h" |
const char *epep_errors[] = { |
"EPEP_ERR_SUCCESS", |
"EPEP_ERR_DATA_DIRECTORY_INDEX_IS_INVALID", |
"EPEP_ERR_SECTION_HEADER_INDEX_IS_INVALID", |
"EPEP_ERR_SYMBOL_INDEX_IS_INVALID", |
"EPEP_ERR_NOT_AN_OBJECT", |
"EPEP_ERR_ADDRESS_IS_OUT_OF_SECTION_RAW_DATA", |
"EPEP_ERR_OUTPUT_CAPACITY_IS_ZERO", |
"EPEP_ERR_OUTPUT_IS_NULL", |
"EPEP_ERR_ADDRESS_IS_OUT_OF_ANY_SECTION", |
"EPEP_ERR_EXPORT_ADDRESS_TABLE_ENTRY_NAME_NOT_FOUND", |
"EPEP_ERR_NO_BASE_RELOCATION_TABLE", |
"EPEP_ERR_BASE_RELOCATION_IS_ALREADY_END", |
"EPEP_ERR_INVALID_DATA_DIRECTORY_OFFSET", |
"EPEP_ERR_INVALID_SECTION_HEADER_OFFSET", |
"EPEP_ERR_INVALID_SECTION_DATA_OFFSET", |
"EPEP_ERR_INVALID_STRING_TABLE_SIZE_OFFSET", |
"EPEP_ERR_INVALID_SYMBOL_OFFSET", |
"EPEP_ERR_INVALID_IMPORT_DIRECTORY_OFFSET", |
"EPEP_ERR_INVALID_IMPORT_DIRECTORY_NAME_OFFSET", |
"EPEP_ERR_INVALID_LOOKUP_OFFSET", |
"EPEP_ERR_INVALID_LOOKUP_NAME_OFFSET", |
"EPEP_ERR_INVALID_EXPORT_TABLE_OFFSET", |
"EPEP_ERR_INVALID_DLL_NAME_OFFSET", |
"EPEP_ERR_INVALID_EXPORT_NAME_POINTER_OFFSET", |
"EPEP_ERR_INVALID_ORDINAL_TABLE_OFFSET", |
"EPEP_ERR_INVALID_EXPORT_NAME_OFFSET", |
"EPEP_ERR_INVALID_EXPORT_ADDRESS_OFFSET", |
"EPEP_ERR_INVALID_FORWARDER_OFFSET", |
"EPEP_ERR_INVALID_BASE_RELOCATION_BLOCK_OFFSET", |
"EPEP_ERR_INVALID_NEXT_BASE_RELOCATION_BLOCK_OFFSET", |
"EPEP_ERR_INVALID_BASE_RELOCATION_BLOCK_BASE_RELOCATION_OFFSET", |
"EPEP_ERR_INVALID_SECTION_RELOCATION_OFFSET", |
"EPEP_ERR_INVALID_LINENUMBER_OFFSET", |
}; |
#define ERROR_EPEP(epep) printf("Error: epep returned %u (%s) at "__FILE__":%u", \ |
(epep)->error_code, epep_errors[(epep)->error_code], __LINE__); exit(-1) |
static int emit_logs; |
static void log_info(const char *fmt, ...) { |
if (emit_logs) { |
va_list ap; |
va_start(ap, fmt); |
vprintf(fmt, ap); |
va_end(ap); |
} |
} |
uint32_t get32(const char *buf, size_t offset) { |
return ((uint32_t)(uint8_t)buf[offset + 0] << 0) |
| ((uint32_t)(uint8_t)buf[offset + 1] << 8) |
| ((uint32_t)(uint8_t)buf[offset + 2] << 16) |
| ((uint32_t)(uint8_t)buf[offset + 3] << 24); |
} |
EpepCoffRelocation get_relocation_for_section_and_offset(Epep *epep, EpepSectionHeader *sh, size_t offset) { |
EpepCoffRelocation rel = { 0 }; |
for (size_t i = 0; i < sh->NumberOfRelocations; i++) { |
if (!epep_get_section_relocation_by_index(epep, sh, &rel, i)) { |
ERROR_EPEP(epep); |
} |
if (rel.VirtualAddress == offset) { |
return rel; |
} |
} |
printf("Error: Can't find relocation of pointer to name of symbol"); |
exit(-1); |
return rel; |
} |
char *read_string(Epep *epep, size_t section_index, size_t offset) { |
EpepSectionHeader sh = { 0 }; |
if (!epep_get_section_header_by_index(epep, &sh, section_index)) { |
ERROR_EPEP(epep); |
} |
char *section = calloc(1, sh.SizeOfRawData); |
if (!epep_get_section_contents(epep, &sh, section)) { |
ERROR_EPEP(epep); |
} |
char *result = strdup(§ion[offset]); |
free(section); |
return result; |
} |
int gendef(const char *obj_path, const char *outname) { |
FILE *out = fopen(outname, "wb"); |
Epep epep; |
{ |
FILE *fp = fopen(obj_path, "rb"); |
if (!fp) { |
printf("Error: Can't open \"%s\"", obj_path); |
exit(-1); |
} |
if (!epep_init(&epep, fp)) { |
ERROR_EPEP(&epep); |
} |
} |
size_t strtab_size = 0; |
if (!epep_get_string_table_size(&epep, &strtab_size)) { |
ERROR_EPEP(&epep); |
} |
char *strtab = malloc(strtab_size); |
if (!epep_get_string_table(&epep, strtab)) { |
ERROR_EPEP(&epep); |
} |
for (size_t sym_i = 0; sym_i < epep.coffFileHeader.NumberOfSymbols; sym_i++) { |
EpepCoffSymbol sym = { 0 }; |
if (!epep_get_symbol_by_index(&epep, &sym, sym_i)) { |
ERROR_EPEP(&epep); |
} |
size_t name_max = 1024; |
char name[name_max]; |
if (sym.symbol.Zeroes == 0) { |
strcpy(name, &strtab[sym.symbol.Offset]); |
} else { |
memcpy(name, sym.symbol.ShortName, 8); |
name[8] = '\0'; |
} |
if (!strcmp(name, "_EXPORTS") || !strcmp(name, "EXPORTS")) { |
fprintf(out, "LIBRARY %s\n\nEXPORTS\n", obj_path); |
size_t export_table_offset_in_section = sym.symbol.Value; |
size_t section_index = sym.symbol.SectionNumber - 1; |
EpepSectionHeader sh = { 0 }; |
if (!epep_get_section_header_by_index(&epep, &sh, section_index)) { |
ERROR_EPEP(&epep); |
} |
size_t section_offset = sh.PointerToRawData; |
size_t export_table_offset = section_offset + export_table_offset_in_section; |
char *section = calloc(1, sh.SizeOfRawData); |
if (!epep_get_section_contents(&epep, &sh, section)) { |
ERROR_EPEP(&epep); |
} |
for (size_t offset = export_table_offset_in_section;; offset += 8) { |
size_t name_offset = get32(section, offset); |
size_t data_offset = get32(section, offset + 4); |
if (name_offset == 0 || data_offset == 0) { |
break; |
} |
EpepCoffRelocation rel = get_relocation_for_section_and_offset(&epep, &sh, offset); |
EpepCoffSymbol name_sym = { 0 }; |
if (!epep_get_symbol_by_index(&epep, &name_sym, rel.SymbolTableIndex)) { |
ERROR_EPEP(&epep); |
} |
size_t name_offset_in_section = name_sym.symbol.Value + name_offset; |
char *name = read_string(&epep, name_sym.symbol.SectionNumber - 1, name_offset_in_section); |
fprintf(out, "%s\n", name); |
} |
break; |
} |
sym_i += sym.symbol.NumberOfAuxSymbols; |
} |
} |
int arg_got_flag(int argc, char **argv, ...) { |
char *arg_names[8]; |
int arg_name_c = 0; |
va_list ap; |
va_start(ap, argv); |
for (char *arg_name = va_arg(ap, char *); arg_name; arg_name = va_arg(ap, char *)) { |
if (arg_name_c >= 8) { |
printf("Internal error: Too many parameter aliases passed to %s", __func__); |
exit(-1); |
} |
arg_names[arg_name_c++] = arg_name; |
} |
va_end(ap); |
for (int i = 1; i < argc; i++) { |
// If an argumetns was handled already then it's NULL here |
if (argv[i] == NULL) { |
continue; |
} |
for (int arg_name_i = 0; arg_name_i < arg_name_c; arg_name_i++) { |
char *arg_name = arg_names[arg_name_i]; |
if (!strcmp(argv[i], arg_name)) { |
argv[i] = NULL; // Do not handle this argument as a input name |
return i; |
} |
} |
} |
return 0; |
} |
char *arg_got_param(int argc, char **argv, char *arg) { |
int i = arg_got_flag(argc, argv, arg, 0); |
if (i == 0) { |
return NULL; |
} |
if (i + 1 >= argc) { |
printf("Warning: %s parameter expects a value (like %s <value>)", arg, arg); |
return NULL; |
} |
char *result = argv[i + 1]; |
argv[i + 1] = NULL; |
return result; |
} |
int usage(char *name, char *remark) { |
if (remark) { |
printf("Error: %s\n\n", remark); |
} |
printf("Usage: %s [option]... [object file name]...\n", name); |
printf(" Generate DEF files from COFF objects\n"); |
printf("\n"); |
printf("Options:\n"); |
printf(" -v, --verbose Emit information logs\n"); |
printf(" -h, --help Output this help and exit\n"); |
return 0; |
} |
int main(int argc, char **argv) { |
if (arg_got_flag(argc, argv, "-h", "-help", "--help", 0)) { |
return usage(argv[0], NULL); |
} |
emit_logs = arg_got_flag(argc, argv, "-v", "-verbose", "--verbose", 0); |
// After handling arguments there only leaven unhandled ones |
// They should be names if inputs. But if there's no input - exit |
int input_file_count = 0; |
for (int i = 1; i < argc; i++) { |
if (argv[i] != NULL) { |
input_file_count++; |
} |
} |
if (input_file_count == 0) { |
return usage(argv[0], "No input file names supplied"); |
} |
for (size_t i = 1; i < argc; i++) { |
char outname[256] = { 0 }; |
sprintf(outname, "%.*s.def", strlen(argv[i]) - strlen(".obj"), argv[i]); |
if (argv[i] != NULL) { |
gendef(argv[i], outname); |
} |
} |
return 0; |
} |