version 1.1
parent
c0c1d72c89
commit
bb68f6cdfa
34
README.md
34
README.md
|
|
@ -1,6 +1,6 @@
|
|||
# C-Scripting
|
||||
|
||||
*Allen Webster. June 28 2026*
|
||||
*Allen Webster. June 28 2026 - July 3 2026*
|
||||
|
||||
The only way forward is inside out.
|
||||
|
||||
|
|
@ -13,6 +13,7 @@ The only way forward is inside out.
|
|||
5. Introduction to the Symbol Set programming primitives.
|
||||
6. Awesome things you can do with C-Scripting.
|
||||
7. The end.
|
||||
8. Change Notes.
|
||||
|
||||
## 1. Start C-Scripting in your C program.
|
||||
|
||||
|
|
@ -121,13 +122,25 @@ SECTIONS {
|
|||
INSERT AFTER .data;
|
||||
```
|
||||
|
||||
#### Windows Version: Self Imaging
|
||||
#### Windows Version: Extended Section Names
|
||||
|
||||
On Windows the tool chain doesn't have anything as nice as a linker script. Instead we pay a little extra compute price on startup using a technique I call "Self Imaging".
|
||||
This section was changed from version 1.0 to 1.1. Credit Martins on the Handmade Network discord for suggesting this possibility.
|
||||
|
||||
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.
|
||||
On Windows the tool chain doesn't have linker scripts, but it does have one simpler feature built in that mostly gets me what I need to do the same thing. On Windows you can name a section like `".sec$extension"`. The part after the `$` is removed by the linker before it becomes your final program. If there are multiple sections with the same base name, but different extensions, then they are concatenated together into one section and sorted alphabetically by their extensions.
|
||||
|
||||
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.
|
||||
So we can place a special sentinel variable at the beginning and end of each symbol set section, and use those variables to locate the symbol set.
|
||||
|
||||
This is roughly how the trick looks:
|
||||
```
|
||||
SEC(".cmd$myspecialsection_a") MyType myspecialsection__begin = {0};
|
||||
SEC(".cmd$myspecialsection_z") MyType myspecialsection__end = {0};
|
||||
|
||||
SEC(".cmd$myspecialsection_m") MyType var1 = {0};
|
||||
SEC(".cmd$myspecialsection_m") MyType var2 = {0};
|
||||
SEC(".cmd$myspecialsection_m") MyType var3 = {0};
|
||||
```
|
||||
|
||||
We have to set aside two copies of our type to setup these sentinels whose memory we never actually use, but this is the most light weight reliable solution so far.
|
||||
|
||||
### Resolving IDs: Pointer Arithmetic
|
||||
|
||||
|
|
@ -167,7 +180,10 @@ The first 5 line block defines a symbol set. For instance if `MY_COMMAND` is the
|
|||
```C
|
||||
#define SYMBOL_SET_DEFINE MY_COMMAND
|
||||
#define MY_COMMAND_Type MyCommand
|
||||
#define MY_COMMAND_section ".sy.mcmd"
|
||||
#define MY_COMMAND_elf_section ".sy.mcmd"
|
||||
#define MY_COMMAND_coff_a_section ".sy$mcmd_a"
|
||||
#define MY_COMMAND_coff_m_section ".sy$mcmd_m"
|
||||
#define MY_COMMAND_coff_z_section ".sy$mcmd_z"
|
||||
#define MY_COMMAND_marker mcmd
|
||||
#include "symbol_set.define.h"
|
||||
```
|
||||
|
|
@ -562,3 +578,9 @@ With this setup, you can start attaching "rules text" to any named symbol so lon
|
|||
This is only the beginning.
|
||||
|
||||
There's a final interpretation of the name C-Scripting that I chose for this project. It's also a reference to "C With Classes" the predecessor to C++. In a similar way C-Scripting is an exploratory project shaping something new out of the raw materials of C. But where I want to go next with this is not a programming language.
|
||||
|
||||
## 8. Change notes.
|
||||
|
||||
1.1 from 1.0:
|
||||
+ Changed the boilerplate for creating a symbol set.
|
||||
+ Eliminated "self imaging" and switched to "sentinels" for locating symbol sets on Windows.
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
set code=%cd%
|
||||
set opts=-FC -GR- -EHa- -nologo -Zi -std:c11 -wd5105
|
||||
set inc=-I%code%\symbol_set
|
||||
if not exist "build" ( mkdir build )
|
||||
pushd build
|
||||
cl -Feexample1 %code%\examples\example1.c %opts% %inc% -link -INCREMENTAL:NO
|
||||
popd
|
||||
|
|
|
|||
|
|
@ -39,7 +39,10 @@ typedef struct EX1_Command{
|
|||
|
||||
#define SYMBOL_SET_DEFINE EX1_COMMAND
|
||||
#define EX1_COMMAND_Type EX1_Command
|
||||
#define EX1_COMMAND_section ".sy.cmd"
|
||||
#define EX1_COMMAND_elf_section ".sy.cmd"
|
||||
#define EX1_COMMAND_coff_a_section ".sy$cmd_a"
|
||||
#define EX1_COMMAND_coff_m_section ".sy$cmd_m"
|
||||
#define EX1_COMMAND_coff_z_section ".sy$cmd_z"
|
||||
#define EX1_COMMAND_marker cmd
|
||||
#include "symbol_set.define.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -166,45 +166,6 @@
|
|||
|
||||
// for CL users: #pragma section(<section>,read,write)
|
||||
|
||||
////////////////////////////////
|
||||
// BEFORE_MAIN(name){ <...> }
|
||||
|
||||
#if SY__OS_WINDOWS
|
||||
|
||||
# pragma section(".CRT$XCU", read)
|
||||
|
||||
# if SY__LANG_CXX
|
||||
|
||||
# define SY__BEFORE_MAIN_(n) \
|
||||
static void n(void); \
|
||||
__declspec(allocate(".CRT$XCU")) \
|
||||
__pragma(comment(linker,"/include:" #n "__")) \
|
||||
extern "C" void (*n##__)(void); \
|
||||
void (*n##__)(void) = n; \
|
||||
static void n(void)
|
||||
|
||||
# else
|
||||
|
||||
# define SY__BEFORE_MAIN_(n) \
|
||||
static void n(void); \
|
||||
__declspec(allocate(".CRT$XCU")) \
|
||||
__pragma(comment(linker,"/include:" #n "__")) \
|
||||
void (*n##__)(void) = n; \
|
||||
static void n(void)
|
||||
|
||||
# endif
|
||||
|
||||
# define SY__BEFORE_MAIN(n) SY__BEFORE_MAIN_(n)
|
||||
|
||||
#elif SY__OS_LINUX
|
||||
|
||||
# define SY__BEFORE_MAIN(n) \
|
||||
__attribute__((constructor)) static void n(void)
|
||||
|
||||
#else
|
||||
# error SY__BEFORE_MAIN missing for this OS
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
// DO_NOT_ELIMINATE
|
||||
|
||||
|
|
|
|||
|
|
@ -7,25 +7,25 @@ extern SyType(SYMBOL_SET_DEFINE) SY__OPL(SYMBOL_SET_DEFINE);
|
|||
#elif SY__OS_WINDOWS
|
||||
|
||||
#if SY__COMPILER_CL
|
||||
# pragma section(SY__GLUE(SYMBOL_SET_DEFINE,_section),read,write)
|
||||
# pragma section(SY__GLUE(SYMBOL_SET_DEFINE,_coff_a_section),read,write)
|
||||
# pragma section(SY__GLUE(SYMBOL_SET_DEFINE,_coff_m_section),read,write)
|
||||
# pragma section(SY__GLUE(SYMBOL_SET_DEFINE,_coff_z_section),read,write)
|
||||
#endif
|
||||
|
||||
#if defined(SY__MAIN)
|
||||
|
||||
SyType(SYMBOL_SET_DEFINE) *SY__FIRST(SYMBOL_SET_DEFINE) = 0;
|
||||
SyType(SYMBOL_SET_DEFINE) *SY__OPL(SYMBOL_SET_DEFINE) = 0;
|
||||
SY__ALIGN_AS_LIT(8)
|
||||
SY__SEC_RW(SY__GLUE(SYMBOL_SET_DEFINE,_coff_a_section))
|
||||
SyType(SYMBOL_SET_DEFINE) SY__FIRST(SYMBOL_SET_DEFINE) = {0};
|
||||
|
||||
SY__BEFORE_MAIN(SY__GLUE(SYMBOL_SET_DEFINE,__init)){
|
||||
int size = sizeof(SY__GLUE(SYMBOL_SET_DEFINE,_section)) - 1;
|
||||
sy__section_init(SY__GLUE(SYMBOL_SET_DEFINE,_section), size,
|
||||
(void**)&SY__FIRST(SYMBOL_SET_DEFINE),
|
||||
(void**)&SY__OPL(SYMBOL_SET_DEFINE));
|
||||
}
|
||||
SY__ALIGN_AS_LIT(8)
|
||||
SY__SEC_RW(SY__GLUE(SYMBOL_SET_DEFINE,_coff_z_section))
|
||||
SyType(SYMBOL_SET_DEFINE) SY__OPL(SYMBOL_SET_DEFINE) = {0};
|
||||
|
||||
#else
|
||||
|
||||
extern SyType(SYMBOL_SET_DEFINE) *SY__FIRST(SYMBOL_SET_DEFINE);
|
||||
extern SyType(SYMBOL_SET_DEFINE) *SY__OPL(SYMBOL_SET_DEFINE);
|
||||
extern SyType(SYMBOL_SET_DEFINE) SY__FIRST(SYMBOL_SET_DEFINE);
|
||||
extern SyType(SYMBOL_SET_DEFINE) SY__OPL(SYMBOL_SET_DEFINE);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,10 @@
|
|||
|
||||
#define SYMBOL_SET_DEFINE ZZZ
|
||||
#define ZZZ_Type Typezz
|
||||
#define ZZZ_section ".sy.secz"
|
||||
#define ZZZ_elf_section ".sy.secz"
|
||||
#define ZZZ_coff_a_section ".sy$secz_a"
|
||||
#define ZZZ_coff_m_section ".sy$secz_m"
|
||||
#define ZZZ_coff_z_section ".sy$secz_z"
|
||||
#define ZZZ_marker secz
|
||||
#include "symbol_set.define.h"
|
||||
|
||||
|
|
@ -58,7 +61,15 @@ static void funczz##N(void *ptr)
|
|||
|
||||
#define SyType(S) SY__GLUE(S,_Type)
|
||||
|
||||
#define SyDeclare(S,N) SY__ALIGN_AS_LIT(8) SY__SEC_RW(S##_section) SyType(S) SY__SYMBOL(S,N)
|
||||
#if SY__OS_WINDOWS
|
||||
# define SY__SDECL(S) SY__SEC_RW(S##_coff_m_section)
|
||||
#elif SY__OS_LINUX
|
||||
# define SY__SDECL(S) SY__SEC_RW(S##_elf_section)
|
||||
#else
|
||||
# error missing implementation symbol set main section decl
|
||||
#endif
|
||||
|
||||
#define SyDeclare(S,N) SY__ALIGN_AS_LIT(8) SY__SDECL(S) 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__))
|
||||
|
||||
|
|
@ -67,8 +78,8 @@ static void funczz##N(void *ptr)
|
|||
#define SyRaw(S,N) (SY__UAddr)(SyAddress(S,N))
|
||||
|
||||
#if SY__OS_WINDOWS
|
||||
# define SyFirst(S) SY__FIRST(S)
|
||||
# define SyOpl(S) SY__OPL(S)
|
||||
# define SyFirst(S) ((&SY__FIRST(S)) + 1)
|
||||
# define SyOpl(S) (&SY__OPL(S))
|
||||
#elif SY__OS_LINUX
|
||||
# define SyFirst(S) (&SY__FIRST(S))
|
||||
# define SyOpl(S) (&SY__OPL(S))
|
||||
|
|
@ -109,104 +120,9 @@ static void funczz##N(void *ptr)
|
|||
#define SY__FIRST(S) SY__FIRST_(S)
|
||||
#define SY__OPL(S) SY__OPL_(S)
|
||||
|
||||
#if SY__OS_WINDOWS
|
||||
void sy__section_init(char *name, SY__U32 name_size, void **first_out, void **opl_out);
|
||||
#endif
|
||||
|
||||
// I dropped this here so that if you copy paste any of the
|
||||
// above and forget to replace Typezz, you'll get auto-int like
|
||||
// behavior from your error messages.
|
||||
#define Typezz int
|
||||
|
||||
#endif //SY__H
|
||||
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
~~~~~~~~~~~~~~~~~~~~~ Function Definitions ~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||
|
||||
#if SY__MAIN && SY__OS_WINDOWS && !defined(SY__MAIN_DEFINITIONS)
|
||||
#define SY__MAIN_DEFINITIONS 1
|
||||
|
||||
#define SY__PE_MSDOS_MAGIC 0x5A4D
|
||||
struct SY__PE_DosHeader{
|
||||
SY__U16 magic;
|
||||
SY__U16 last_page_size;
|
||||
SY__U16 page_count;
|
||||
SY__U16 reloc_count;
|
||||
SY__U16 paragraph_header_size;
|
||||
SY__U16 min_paragraph;
|
||||
SY__U16 max_paragraph;
|
||||
SY__U16 init_ss;
|
||||
SY__U16 init_sp;
|
||||
SY__U16 checksum;
|
||||
SY__U16 init_ip;
|
||||
SY__U16 init_cs;
|
||||
SY__U16 reloc_table_file_off;
|
||||
SY__U16 overlay_number;
|
||||
SY__U16 reserved[4];
|
||||
SY__U16 oem_id;
|
||||
SY__U16 oem_info;
|
||||
SY__U16 reserved2[10];
|
||||
SY__U32 coff_file_offset;
|
||||
};
|
||||
#define SY__PE_SIGNATURE 0x00004550
|
||||
struct SY__PE_CoffHeader{
|
||||
SY__U16 machine_type;
|
||||
SY__U16 section_count;
|
||||
SY__U32 time_stamp;
|
||||
SY__U32 symbol_table_foff;
|
||||
SY__U32 symbol_count;
|
||||
SY__U16 optional_header_size;
|
||||
SY__U16 flags;
|
||||
};
|
||||
struct SY__PE_SectionHeader{
|
||||
SY__U8 name[8];
|
||||
SY__U32 vsize;
|
||||
SY__U32 voff;
|
||||
SY__U32 fsize;
|
||||
SY__U32 foff;
|
||||
SY__U32 relocations_foff;
|
||||
SY__U32 line_numbers_foff;
|
||||
SY__U16 relocation_count;
|
||||
SY__U16 line_number_count;
|
||||
SY__U32 flags;
|
||||
};
|
||||
|
||||
void
|
||||
sy__section_init(char *name, SY__U32 name_size,
|
||||
void **first_out, void **opl_out){
|
||||
if (name_size <= 8){
|
||||
extern SY__U8 __ImageBase[];
|
||||
SY__U8 *base = __ImageBase;
|
||||
struct SY__PE_DosHeader *dos = (struct SY__PE_DosHeader*)base;
|
||||
if (dos->magic == SY__PE_MSDOS_MAGIC){
|
||||
SY__U32 *pe_signature = (SY__U32*)(base + dos->coff_file_offset);
|
||||
if (*pe_signature == SY__PE_SIGNATURE){
|
||||
struct SY__PE_CoffHeader *coff = (struct SY__PE_CoffHeader*)(pe_signature + 1);
|
||||
SY__U32 sections_offset = (dos->coff_file_offset + sizeof(*pe_signature) +
|
||||
sizeof(*coff) + coff->optional_header_size);
|
||||
SY__U32 section_count = coff->section_count;
|
||||
struct SY__PE_SectionHeader*
|
||||
section = (struct SY__PE_SectionHeader*)(base + sections_offset);
|
||||
for (SY__U32 i = 0; i < section_count; i += 1, section += 1){
|
||||
SY__B32 match = 1;
|
||||
for (SY__U32 j = 0; j < 8; j += 1){
|
||||
if (name[j] != section->name[j]){
|
||||
match = 0;
|
||||
break;
|
||||
}
|
||||
if (name[j] == 0){
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (match){
|
||||
*first_out = base + section->voff;
|
||||
*opl_out = base + section->voff + section->vsize;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif //SY__MAIN_DEFINITIONS
|
||||
|
|
|
|||
Loading…
Reference in New Issue