diff --git a/README.md b/README.md index 0d8d97a..881ef3e 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ The only way forward is inside out. 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 +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 be able to use the compiled program when you are building with `symbol_set` on Linux. 3. In any compilation unit where you are going to be C-Scripting, `#include "symbol_set.h"`. @@ -44,7 +44,7 @@ When you define a symbol, you specify which symbol set it belongs to. The symbol You can imagine it looks sort of like this: ```C -// define my Command type +// define MyCommand type which I will underly the symbol set struct MyCommand{ String8 name; String8 description; @@ -54,7 +54,7 @@ struct MyCommand{ // define the MY_COMMAND symbol set SYMBOL_SET_DEFINE(MY_COMMAND, MyCommand); -// define some commands +// define symbols in the MY_COMMAND symbol set (ie define commands) MY_COMMAND_DEFINE(Foo, "Do Foo."){ do_foo(ctx); } @@ -66,7 +66,7 @@ MY_COMMAND_DEFINE(EasyBar, "If it's not too hard, do Bar."){ } ``` -You can then use these symbols essentially as if you had written the non C-Scripted version shown below: +Code structured very similarly to the above ends up with semantics that would be like having all that data, and all those function bodies organized into a single addressable table, and a corresponding enum: ``` void mycommand__Foo(void*){ do_foo(ctx); @@ -88,7 +88,7 @@ MyCommand MY_COMMAND_array[] = { }; ``` -So you can loop over the array, and statically reference the symbol names to get indices into the array. +You can loop over the array of symbols. And you can statically reference the symbol names to get indices into the array, or just to compare ids, create run-time lists of symbols, etc. ## 3. How does it work? @@ -98,7 +98,7 @@ Under the hood, symbol sets are implemented by assigning each one a special data 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. +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, and lay them out into a single array. C doesn't have a feature that works this way on purpose. But any compiler that has 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 data sections. And that's why use data sections for this. ### Locating Data Sections @@ -127,7 +127,7 @@ On Windows the tool chain doesn't have anything as nice as a linker script. Inst 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. +This is implemented in `symbol_set.h` under `Function Definitions`. 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 diff --git a/symbol_set.c b/symbol_set.c deleted file mode 100644 index 396f9db..0000000 --- a/symbol_set.c +++ /dev/null @@ -1,91 +0,0 @@ -/*********************************************************** -** symbol_set - A public domain C modifier library -** by Allen Webster, "Mr. 4th", allenw@mr4th.com -** -** No warranty implied; use at your own risk -** -** Read README to get started. -*/ - -#if SY__OS_WINDOWS - -#pragma pack(push,1) -#define SY__DOS_MAGIC 0x5A4D -typedef struct Sy__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_offset; -} Sy__DosHeader; -typedef struct Sy__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; -} Sy__CoffHeader; -typedef struct Sy_CoffSection{ - 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; -} Sy_CoffSection; -#pragma pack(pop) - -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; - Sy__DosHeader *dos = (Sy__DosHeader*)base; - if (dos_header->magic == SY__DOS_MAGIC){ - Sy__CoffHeader *coff = (Sy__CoffHeader*)(base + dos->coff_offset); - Sy_U32 sections_offset = (dos->coff_offset + sizeof(*coff) + - coff->optional_header_size); - Sy_U32 section_count = coff->section_count; - Sy_CoffSection *section = (Sy_CoffSection*)(base + sections_offset); - for (Sy_U32 i = 0; i < section_count; i += 1, section += 1){ - int 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 diff --git a/symbol_set.define.h b/symbol_set.define.h deleted file mode 100644 index 8bc041e..0000000 --- a/symbol_set.define.h +++ /dev/null @@ -1,31 +0,0 @@ -#if SY__OS_LINUX - -int spider; - -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 COMPILER_CL -# pragma section(SY__GLUE(SYMBOL_SET_DEFINE,_section),read,write) -#endif - -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; - void *first = 0; - void *opl = 0; - sy__section_init(SY__GLUE(SYMBOL_SET_DEFINE,_section), size, - (void**)&SY__FIRST(SYMBOL_SET_DEFINE), - (void**)&SY__OPL(SYMBOL_SET_DEFINE)); -} - -#else -# error symbol_set.define not implemented for this OS -#endif - -#undef SYMBOL_SET_DEFINE \ No newline at end of file diff --git a/symbol_set.h b/symbol_set.h deleted file mode 100644 index 4513fe3..0000000 --- a/symbol_set.h +++ /dev/null @@ -1,308 +0,0 @@ -/*********************************************************** -** symbol_set - A public domain C modifier library -** by Allen Webster, "Mr. 4th", allenw@mr4th.com -** -** No warranty implied; use at your own risk -** -** Read README to get started. -*/ - -#ifndef SYMBOL_SET_H -#define SYMBOL_SET_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 -# 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 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 -# else -# error missing 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 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__LANG_CXX 1 -#else -# define SY__LANG_C 1 -#endif - -#if !defined(SY__LANG_CXX) -# define SY__LANG_CXX 0 -#endif -#if !defined(SY__LANG_C) -# define SY__LANG_C 0 -#endif - -/********** -** Types ** -**********/ - -#include - -typedef uint8_t Sy_U8; -typedef uint16_t Sy_U16; -typedef uint32_t Sy_U32; -typedef uint64_t Sy_U64; - -#if SY__ARCH_X64 || SY__ARCH_ARM64 -typedef Sy_U64 Sy_UAddress; -#else -typedef Sy_U32 Sy_UAddress; -#endif - -/****************** -** Macro Helpers ** -******************/ - -#define SY__GLUE_(a,b) a##b -#define SY__GLUE(a,b) SY__GLUE_(a,b) - -#define SY__STRIFY_(s) #s -#define SY__STRIFY(s) SY__STRIFY_(s) - -/***************** -** Align Helper ** -*****************/ - -#define SY__ALIGN_TO_POW2(x,a) (((x) + (a) - 1)&~((a) - 1)) - -/******************* -** Section Macros ** -*******************/ - -/* IMPORTANT! On CL compiler add: #pragma section(
,read,write) */ - -#if SY__COMPILER_CLANG || SY__COMPILER_GCC -# if SY__OS_MAC -# define SY__SECTION_READONLY(N) __attribute__((__section__("__TEXT,"N))) const -# define SY__SECTION_READWRITE(N) __attribute__((__section__("__READ,"N))) -# else -# define SY__SECTION_READONLY(N) __attribute__((__section__(N))) const -# define SY__SECTION_READWRITE(N) __attribute__((__section__(N))) -# endif -#elif COMPILER_CL -# define SY__SECTION_READONLY(N) __declspec(allocate(N)) const -# define SY__SECTION_READWRITE(N) __declspec(allocate(N)) -#else -# error SY__SECTION_* not defined for this compiler/OS -#endif - -/**************************** -** Do Not Mangle Qualifier ** -****************************/ - -#if SY__LANG_CXX -# define SY__DO_NOT_MANGLE extern "C" -#else -# define SY__DO_NOT_MANGLE -#endif - -/******************************* -** Do Not Eliminate Qualifier ** -*******************************/ - -#if SY__OS_WINDOWS -# define SY__DO_NOT_ELIMINATE__S0(N) __pragma(comment(linker,"/include:" #N)) -# define SY__DO_NOT_ELIMINATE__S1(N) DO_NOT_ELIMINATE__S0(N) -# define SY__DO_NOT_ELIMINATE(N) DO_NOT_ELIMINATE__S1(N) -#else -# define SY__DO_NOT_ELIMINATE(N) -#endif - -/******************** -** Align Qualifier ** -********************/ - -#if SY__COMPILER_CL -# define SY__ALIGN_VAR(z) __declspec(align(z)) -#elif SY__COMPILER_CLANG || SY__COMPILER_GCC -# define SY__ALIGN_VAR(z) __attribute__((__aligned__(z))) -#else -# error SY__ALIGN not defined for this compiler -#endif - -/***************** -** Before Mains ** -*****************/ - -#if SY__OS_WINDOWS -# pragma section(".CRT$XCU", read) -# define SY__BEFORE_MAIN__(n) \ -static void n(void); \ -SY__SECTIONREADWRITE(".CRT$XCU") \ -SY__DO_NOT_ELIMINATE(n##__) \ -SY__DO_NOT_MANGLE void (*n##__)(void); \ -void (*n##__)(void) = n; \ -static void n(void) -#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 - -#define SY__BEFORE_MAIN_(n) SY__BEFORE_MAIN__(n) -#define SY__BEFORE_MAIN(n) SY__BEFORE_MAIN_(n) - -/************************************* -** Symbol Set Programming Interface ** -*************************************/ - -#define SyType(S) SY__GLUE(S,_Type) - -#define SyDeclare(S,N) SY__ALIGN_VAR(8) SY__SECTION_READWRITE(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 SyFlag(S,N) (1llu << SyID(S,N)) - -#define SyStride(S) SY__ALIGN_TO_POW2(sizeof(SyType(S)), 8) - -#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 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= 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, syname); - hash_buckets_expand(&buckets, symbol_set_names.node_count); - hash_buckets_insert(arena, &buckets, hash, IntFromPtr(symbol_set_names.last)); - } - } - } - - } - - // print output linker script - STREAM *stream = stream_new(); - - stream_printf(stream, - "SECTIONS {\n" - " .sy : {\n"); - - for (String8Node *node = symbol_set_names.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); -} diff --git a/symbol_set.starter.h b/symbol_set.starter.h deleted file mode 100644 index eb79bec..0000000 --- a/symbol_set.starter.h +++ /dev/null @@ -1,89 +0,0 @@ -/*********************************************************** -** symbol_set - A public domain C modifier library -** by Allen Webster, "Mr. 4th", allenw@mr4th.com -** -** No warranty implied; use at your own risk -** -** Read README to get started. -*/ - - - -/**************************** -***************************** -********** Setup ********** -***************************** -****************************/ -#if 0 -/* In ever compilation unit, #include "symbol_set.h" once before using -** any symbol set features or defining a symbol set. */ -#include "symbol_set.h" - -/* In one compilation unit, #include "symbol_set.c" */ -#include "symbol_set.c" -#endif - - - -/****************************************** -******************************************* -********** Define A Symbol Set ********** -******************************************* -******************************************/ -#if 0 -/* To define a symbol set, copy-paste the block below and then: -** Replace ZZZ with a name for the symbol set. -** Replace Typezz with the type of the symbol set. -** Replace secz with a unique name for the data section of the symbol set. -** IMPORTANT NOTE: only use 4 characters for the section name if you -** want to port to Windows. -*/ - -#define SYMBOL_SET_DEFINE ZZZ -#define ZZZ_Type Typezz -#define ZZZ_section ".sy.secz" -#define ZZZ_marker secz -#include "symbol_set.define.h" - -#endif - - - -/**************************************************** -***************************************************** -********** Common Symbol Defining Macros ********** -***************************************************** -****************************************************/ -#if 0 - -/* Define a basic struct with a NAME */ -#define ZZZ_DEF(N,...) SyDefine(ZZZ, NAME) = { ... } - -/* Define a basic struct without a name */ -#define ZZZ_DEF(...) SyDefineUnnamed(ZZZ, NAME) = { ... } - -/* Define a struct with a NAME & attach a function. -** Replace zzzprefix with a unique function prefix. - ** Update the parameter and return types as needed. -*/ -#define ZZZ_DEF(N,...) \ -void zzzprefix_##N(void); \ -SyDefine(ZZZ, NAME) = { ..., zzzprefix_##N }; \ -void zzzprefix_##N(void) - -/* Define a struct with a NAME & attach multiple functions -** Replace zzzprefix1... with unique function prefixes. -** Update the parameter and return types as needed. -** Replace ZZZ_PREFIX1... with appropriate names. -*/ -#define ZZZ_DEF(N,...) \ -void zzzprefix1_##N(void); \ -void zzzprefix2_##N(void); \ -SyDefine(ZZZ, NAME) = { ..., zzzprefix1_##N, zzzprefix2_##N } - -#define ZZZ_PREFIX1(N) void zzzprefix1_##N(void) -#define ZZZ_PREFIX2(N) void zzzprefix2_##N(void) - -#endif - - diff --git a/symbol_set/symbol_set.h b/symbol_set/symbol_set.h index e5e6f94..172d456 100644 --- a/symbol_set/symbol_set.h +++ b/symbol_set/symbol_set.h @@ -123,11 +123,9 @@ void sy__section_init(char *name, SY__U32 name_size, void **first_out, void **op /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~ Function Definitions ~~~~~~~~~~~~~~~~~~~~~~~~~*/ -#if SY__MAIN && !defined(SY__MAIN_DEFINITIONS) +#if SY__MAIN && SY__OS_WINDOWS && !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; @@ -211,6 +209,4 @@ sy__section_init(char *name, SY__U32 name_size, } } -#endif /* SY__OS_WINDOWS */ - #endif //SY__MAIN_DEFINITIONS