-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
256 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
lib*.a | ||
demo/demo | ||
demo/*.exe | ||
.vscode | ||
/obj |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# is-odd-jit License Agreement | ||
### Inheritance Statement | ||
This License Agreement for the "is-odd-jit" project (the "License") is an extension and continuation of the license terms set forth by the original "is-odd" project. The "is-odd-jit" project inherits its licensing framework, stipulations, and legal enforceability from the "is-odd" project. By accessing, using, modifying, or distributing the "is-odd-jit" software, you acknowledge and agree that this License is bound by and subject to the terms of the "is-odd" project's license. | ||
|
||
The original "is-odd" license serves as the foundational legal document governing the use, modification, and distribution of the "is-odd-jit" software. All clauses, conditions, restrictions, and legal obligations contained within the "is-odd" license are fully applicable to the "is-odd-jit" project. Any interpretation, enforcement, or adjudication of the terms of this License shall be conducted with reference to the original "is-odd" license. | ||
|
||
For the avoidance of doubt, the rights, responsibilities, and restrictions that apply to the "is-odd" project, as specified in its license, are hereby fully transferred to and incorporated within the "is-odd-jit" project. Users, developers, and distributors of the "is-odd-jit" software are required to adhere strictly to the licensing terms established by the "is-odd" project. | ||
|
||
This inheritance of licensing terms ensures consistency and continuity in the legal framework governing the "is-odd" and "is-odd-jit" projects. Any provisions, disclaimers, and conditions originally articulated in the "is-odd" license are fully enforceable within the context of the "is-odd-jit" project. As such, any use, modification, or distribution of the "is-odd-jit" software must be conducted in compliance with the inherited license terms. | ||
|
||
It is important to note that the "is-odd-jit" project does not introduce any new licensing terms or modify the existing terms of the "is-odd" license. Instead, it upholds and perpetuates the legal and ethical standards set forth by the "is-odd" project. This ensures that the intellectual property rights, restrictions on usage, and legal disclaimers remain intact and are consistently applied to both projects. | ||
|
||
By engaging with the "is-odd-jit" software, you confirm your acceptance of these inherited terms and acknowledge that any legal actions, interpretations, or disputes will be governed by the original "is-odd" license. This acknowledgment reinforces the binding nature of the inherited license and underscores your obligation to comply with its terms. | ||
|
||
## is-odd License | ||
Do not use |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
CC = gcc | ||
|
||
CFLAGS = -Wall -Werror -fPIC | ||
|
||
SRC_DIR = src | ||
OBJ_DIR = obj/$(OS) | ||
|
||
SOURCES = $(wildcard $(SRC_DIR)/*.c) | ||
OBJECTS = $(patsubst $(SRC_DIR)/%.c, $(OBJ_DIR)/%.o, $(SOURCES)) | ||
|
||
OUTPUT_NAME = libisodd-$(OS).a | ||
|
||
all: $(OBJ_DIR) $(OUTPUT_NAME) | ||
|
||
# Create object directory if it doesn't exist | ||
$(OBJ_DIR): | ||
mkdir -p $(OBJ_DIR) | ||
|
||
$(OUTPUT_NAME): $(OBJECTS) | ||
$(AR) rcs $@ $^ | ||
|
||
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c | ||
$(CC) $(CFLAGS) $(OS_CFLAGS) -c $< -o $@ | ||
|
||
# Detect OS and set appropriate flags | ||
ifeq ($(OS),windows) | ||
CC = x86_64-w64-mingw32-gcc | ||
AR = x86_64-w64-mingw32-ar | ||
OS_CFLAGS = -DWIN32 -I/usr/share/mingw-w64/include/ | ||
LDFLAGS = -Wl,--out-implib,libisodd.a | ||
else ifeq ($(OS),linux) | ||
OS_CFLAGS = | ||
else | ||
$(error Unknown OS specified. Please set 'OS' to one of: 'windows', 'linux') | ||
endif | ||
|
||
clean: | ||
rm -rf $(OBJ_DIR) $(OUTPUT_NAME) $(DYNAMIC_LIB) | ||
|
||
.PHONY: all clean |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
#include <stdint.h> | ||
#include <stdio.h> | ||
|
||
#include "../include/isodd.h" | ||
|
||
int main() { | ||
while (1) { | ||
printf("input: "); | ||
|
||
uint16_t value; | ||
if (scanf("%hu", &value) != 1) { | ||
fprintf(stderr, "invalid input, exiting\n"); | ||
return 1; | ||
} | ||
|
||
printf(is_odd(value) ? "%hu is odd\n" : "%hu is even\n", value); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
(cd .. && make OS=linux) | ||
gcc -o demo main.c -L.. -lisodd-linux | ||
./demo |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
wsl make -C .. OS=windows | ||
wsl x86_64-w64-mingw32-gcc -o demo.exe main.c -L.. -lisodd-windows -lkernel32 | ||
demo.exe |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
#pragma once | ||
|
||
#include <stdbool.h> | ||
#include <stdint.h> | ||
|
||
// Determines whether a number is even or odd. | ||
extern bool is_odd(uint64_t value); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# is-odd-jit | ||
the **is-odd-jit** library is a *blazing* fast way to tell whether a number is even or odd - now leveraging **just-in-time (JIT) compilation!** (ノ◕ヮ◕)ノ*:・゚✧ | ||
|
||
> [!TIP] | ||
> you also may be interested in the previous, web version, [ascpixi/is-odd](https://github.com/ascpixi/is-odd)! | ||
in order to use is-odd-jit, compile the library under Linux via `make OS=linux` or `make OS=windows` in the root repository directory - for Windows, you'll also need to run `sudo apt-get install gcc-mingw-w64`. | ||
|
||
this will produce a static library named `libisodd-<os>.a` (where `<os>` is the OS the library was compiled for), that you can reference like any other! see the [demo](./demo/) for more details! | ||
|
||
currently, the only supported architecture is **x86-64**, and the supported ABIs are System V (most Unices) and the Microsoft x64 (Windows). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
#pragma once | ||
|
||
#include "arch.h" | ||
|
||
#ifdef __x86_64 | ||
#ifdef WIN32 | ||
// Microsoft x64 ABI | ||
#define CALLCONV_ARG1 X86_RM_CX | ||
#else | ||
// System V x64 ABI | ||
#define CALLCONV_ARG1 X86_RM_DI | ||
#endif | ||
#else | ||
#error Unsupported architecture. | ||
#endif | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
#pragma once | ||
|
||
#ifdef __x86_64 | ||
#define X86_RM_AX 0 | ||
#define X86_RM_CX 1 | ||
#define X86_RM_DX 2 | ||
#define X86_RM_BX 3 | ||
#define X86_RM_SP 4 | ||
#define X86_RM_BP 5 | ||
#define X86_RM_SI 6 | ||
#define X86_RM_DI 7 | ||
|
||
#define X86_OPSIZE_OVERRIDE 0x66 | ||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
#include <stdint.h> | ||
#include <stdbool.h> | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include "abi.h" | ||
#include "os.h" | ||
|
||
typedef bool (*fnptr_is_odd_jitted)(uint64_t value); | ||
|
||
static fnptr_is_odd_jitted emitted_code; | ||
|
||
#if __x86_64 | ||
static fnptr_is_odd_jitted compile() { | ||
// the maximum size for the generated function is equal to: | ||
// - for each value... | ||
// - 5 bytes for CMP | ||
// - 6 bytes for JE rel32 | ||
// - ...and for the two outcomes: | ||
// - even: | ||
// - xor rax, rax 3 bytes | ||
// - ret 1 byte | ||
// - odd: | ||
// - mov rax, 1 7 bytes | ||
// - ret 1 byte | ||
// we could encode the JE as rel8 or rel16, but this would complicate matters | ||
// (calculation of jump distances would be harder), and I really cannot be bothered! ;3c | ||
|
||
uint32_t max_size = ((5 + 6) * 0xffff) + 8 + 4; | ||
|
||
void *memory = malloc(max_size); | ||
uint8_t *current = memory; | ||
|
||
for (uint16_t i = 0; i < 0xffff; i++) { | ||
// CMP r/m16, imm16 [81 /7 iw] | ||
*current++ = X86_OPSIZE_OVERRIDE; | ||
*current++ = 0x81; | ||
*current++ = 0b11111000 | CALLCONV_ARG1; | ||
*(uint16_t*)current = i; | ||
current += sizeof(uint16_t); | ||
|
||
uint32_t jmp_distance = (0xffff - i) * (5 + 6) - 11; | ||
uint32_t target = (i % 2 == 0) ? 0 : 4; // even? then offset is 0; else, skip "xor rax, rax" and "ret" | ||
|
||
// JE imm32 [0F 84 cd] | ||
*current++ = 0x0F; | ||
*current++ = 0x84; | ||
*(uint32_t*)current = jmp_distance + target; | ||
current += sizeof(uint32_t); | ||
} | ||
|
||
// Emit return functions | ||
|
||
// +0 even: | ||
*current++ = 0x48; // xor rax, rax | ||
*current++ = 0x31; | ||
*current++ = 0xC0; | ||
|
||
*current++ = 0xC3; // ret | ||
|
||
// +4 odd: | ||
*current++ = 0x48; // mov rax, 1 | ||
*current++ = 0xC7; | ||
*current++ = 0xC0; | ||
*(uint32_t*)current = 1; | ||
current += sizeof(uint32_t); | ||
|
||
*current++ = 0xC3; // ret | ||
|
||
// Convert the read-write memory to read-execute (will copy) | ||
void *fn = os_make_executable(max_size, memory); | ||
free(memory); | ||
return fn; | ||
} | ||
#else | ||
#error Code generation is not defined for this architecture. | ||
#endif | ||
|
||
bool is_odd(uint64_t value) { | ||
if (emitted_code != NULL) | ||
return emitted_code(value); // function was JIT-ted before | ||
|
||
fnptr_is_odd_jitted func = compile(); | ||
emitted_code = func; | ||
return func(value); | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
#if WIN32 | ||
|
||
#include <windows.h> | ||
|
||
void* os_make_executable(size_t bytes, void* buffer) { | ||
DWORD unused; | ||
|
||
void *out = VirtualAlloc(NULL, bytes, MEM_COMMIT, PAGE_READWRITE); | ||
memcpy(out, buffer, bytes); | ||
VirtualProtect(out, bytes, PAGE_EXECUTE_READ, &unused); | ||
return out; | ||
} | ||
|
||
#else | ||
|
||
#include <sys/mman.h> | ||
#include <string.h> | ||
|
||
void* os_make_executable(size_t bytes, void* buffer) { | ||
void *out = mmap(0, bytes, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | ||
memcpy(out, buffer, bytes); | ||
return out; | ||
} | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
#pragma once | ||
|
||
#include <stdint.h> | ||
|
||
// Allocates an executable memory region, copies the memory region described by | ||
// "bytes" and "buffer", and changes the allocated buffer to be read-only. | ||
// | ||
// Returns the allocated buffer. | ||
void* os_make_executable( | ||
size_t bytes, | ||
void *buffer | ||
); |