elf.c: section limit inference for linux, fixes for stb_ds.h hashing, more compilation flags

This commit is contained in:
veclav talica 2024-07-28 01:44:39 +03:00
parent 36dcf14db7
commit 5ddf0eb879
9 changed files with 137 additions and 33 deletions

View File

@ -23,6 +23,14 @@ add_subdirectory(third-party/physfs)
add_subdirectory(third-party/libxm) add_subdirectory(third-party/libxm)
if(UNIX)
set(SYSTEM_SOURCE_FILES
src/system/linux/elf.c
)
else()
set(SYSTEM_SOURCE_FILES)
endif()
set(SOURCE_FILES set(SOURCE_FILES
third-party/physfs/extras/physfsrwops.c third-party/physfs/extras/physfsrwops.c
third-party/stb/stb_vorbis.c third-party/stb/stb_vorbis.c
@ -49,6 +57,8 @@ set(SOURCE_FILES
src/game/scenes/scene.c src/game/scenes/scene.h src/game/scenes/scene.c src/game/scenes/scene.h
src/game/scenes/title.c src/game/scenes/title.h src/game/scenes/title.c src/game/scenes/title.h
src/game/scenes/ingame.c src/game/scenes/ingame.h src/game/scenes/ingame.c src/game/scenes/ingame.h
${SYSTEM_SOURCE_FILES}
) )
# target # target
@ -90,19 +100,24 @@ else()
# these SHOULDN'T break anything... # these SHOULDN'T break anything...
-fno-math-errno -fno-math-errno
-ffp-contract=fast -ffp-contract=fast
-fno-signed-zeros -fno-signed-zeros)
-fno-trapping-math
-freciprocal-math)
set(BUILD_FLAGS_RELEASE set(BUILD_FLAGS_RELEASE
-O3
-flto -flto
-Wl,-gc-sections -Wl,-gc-sections
-fdata-sections -fdata-sections
-ffunction-sections) -ffunction-sections
-funroll-loops
-fomit-frame-pointer
-fallow-store-data-races)
set(BUILD_FLAGS_DEBUG set(BUILD_FLAGS_DEBUG
-O0
-g3 -g3
-gdwarf -gdwarf
-fno-omit-frame-pointer
-fstack-protector-all
-fsanitize=undefined -fsanitize=undefined
-fsanitize-trap=undefined) -fsanitize=address)
target_compile_options(${PROJECT_NAME} PRIVATE target_compile_options(${PROJECT_NAME} PRIVATE
${WARNING_FLAGS} ${WARNING_FLAGS}
${BUILD_FLAGS} ${BUILD_FLAGS}

View File

@ -244,7 +244,7 @@ static void audio_sample_and_mixin_channel(const struct audio_channel *channel,
static uint8_t buffer[16384]; static uint8_t buffer[16384];
const int int16_buffer_frames = sizeof (buffer) / sizeof (int16_t); const int int16_buffer_frames = sizeof (buffer) / sizeof (int16_t);
const int float_buffer_frames = sizeof (buffer) / sizeof (float); const int float_buffer_frames = sizeof (buffer) / sizeof (float);
const int stream_frames = len / sizeof (int16_t); const int stream_frames = len / (int)(sizeof (int16_t));
switch (channel->file_type) { switch (channel->file_type) {
case audio_file_type_ogg: { case audio_file_type_ogg: {

View File

@ -65,6 +65,7 @@ static void ingame_end(struct state *state) {
struct scene_ingame *scn = (struct scene_ingame *)state->scene; struct scene_ingame *scn = (struct scene_ingame *)state->scene;
player_destroy(scn->player); player_destroy(scn->player);
world_destroy(scn->world); world_destroy(scn->world);
free(state->scene);
} }

View File

@ -24,6 +24,7 @@ static void title_end(struct state *state) {
struct scene_title *scn = (struct scene_title *)state->scene; struct scene_title *scn = (struct scene_title *)state->scene;
player_destroy(scn->player); player_destroy(scn->player);
world_destroy(scn->world); world_destroy(scn->world);
free(state->scene);
} }

View File

@ -95,7 +95,6 @@ union uncolored_space_triangle {
/* batch of primitives with overlapping properties */ /* batch of primitives with overlapping properties */
struct mesh_batch { struct mesh_batch {
GLuint buffer; /* server side storage */ GLuint buffer; /* server side storage */
size_t buffer_len; /* element count */
uint8_t *primitives; uint8_t *primitives;
}; };

68
src/system/linux/elf.c Normal file
View File

@ -0,0 +1,68 @@
#include "elf.h"
#include <fcntl.h>
#include <unistd.h>
#include <sys/auxv.h>
#include <elf.h>
#include <linux/limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
bool infer_elf_section_bounds(const char *const restrict name,
const char **restrict vm_start,
const char **restrict vm_end)
{
bool result = false;
char buf[PATH_MAX];
ssize_t l = readlink("/proc/self/exe", buf, PATH_MAX);
if (l == -1)
goto ERR_CANT_READLINK;
buf[l] = 0; /* readlink() doesn't write a terminator */
int elf = open(buf, O_RDONLY);
if (elf == -1)
goto ERR_CANT_OPEN_SELF;
/* elf header */
Elf64_Ehdr ehdr;
read(elf, &ehdr, sizeof ehdr);
if (ehdr.e_ident[EI_MAG0] != ELFMAG0 ||
ehdr.e_ident[EI_MAG1] != ELFMAG1 ||
ehdr.e_ident[EI_MAG2] != ELFMAG2 ||
ehdr.e_ident[EI_MAG3] != ELFMAG3)
goto ERR_NOT_ELF;
/* section header string table */
Elf64_Shdr shstrdr;
lseek(elf, ehdr.e_shoff + ehdr.e_shstrndx * sizeof (Elf64_Shdr), SEEK_SET);
read(elf, &shstrdr, sizeof shstrdr);
char *sh = malloc(shstrdr.sh_size);
lseek(elf, shstrdr.sh_offset, SEEK_SET);
read(elf, sh, shstrdr.sh_size);
/* walk sections searching for needed name */
lseek(elf, ehdr.e_shoff, SEEK_SET);
for (size_t s = 0; s < ehdr.e_shnum; ++s) {
Elf64_Shdr shdr;
read(elf, &shdr, sizeof shdr);
if (strcmp(&sh[shdr.sh_name], name) == 0) {
result = true;
*vm_start = getauxval(AT_ENTRY) - ehdr.e_entry + (char *)shdr.sh_addr;
*vm_end = getauxval(AT_ENTRY) - ehdr.e_entry + (char *)shdr.sh_addr + shdr.sh_size;
break;
}
}
free(sh);
ERR_NOT_ELF:
close(elf);
ERR_CANT_OPEN_SELF:
ERR_CANT_READLINK:
return result;
}

10
src/system/linux/elf.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef ELF_H
#define ELF_H
#include <stdbool.h>
bool infer_elf_section_bounds(const char *restrict name,
const char **restrict vm_start,
const char **restrict vm_end);
#endif

View File

@ -295,8 +295,9 @@ void textures_dump_atlases(struct texture_cache *cache) {
static t_texture_key textures_load(struct texture_cache *cache, const char *path) { static t_texture_key textures_load(struct texture_cache *cache, const char *path) {
/* no need to do anything if it was loaded already */ /* no need to do anything if it was loaded already */
if (shgeti(cache->hash, path) >= 0) const ptrdiff_t i = shgeti(cache->hash, path);
return (t_texture_key){0}; if (i >= 0)
return (t_texture_key){ (uint16_t)i };
SDL_Surface *surface = image_to_surface(path); SDL_Surface *surface = image_to_surface(path);
struct texture new_texture = {0}; struct texture new_texture = {0};
@ -308,12 +309,12 @@ static t_texture_key textures_load(struct texture_cache *cache, const char *path
upload_texture_from_surface(new_texture.loner_texture, surface); upload_texture_from_surface(new_texture.loner_texture, surface);
new_texture.srcrect = (t_rect) { .w = surface->w, .h = surface->h }; new_texture.srcrect = (t_rect) { .w = surface->w, .h = surface->h };
shput(cache->hash, path, new_texture); shput(cache->hash, path, new_texture);
return (t_texture_key){ shgeti(cache->hash, path) }; return (t_texture_key){ (uint16_t)shgeti(cache->hash, path) };
} else { } else {
new_texture.atlas_index = cache->atlas_index; new_texture.atlas_index = cache->atlas_index;
shput(cache->hash, path, new_texture); shput(cache->hash, path, new_texture);
cache->is_dirty = true; cache->is_dirty = true;
return (t_texture_key){ shgeti(cache->hash, path) }; return (t_texture_key){ (uint16_t)shgeti(cache->hash, path) };
} }
} }
@ -363,35 +364,44 @@ void textures_update_atlas(struct texture_cache *cache) {
} }
/* EXPERIMANTAL: LIKELY TO BE REMOVED! */ /* EXPERIMANTAL: LIKELY TO BE REMOVED! */
/* todo: If it's proven to be useful: add runtime checking for .rodata > .data */ #ifdef __linux__ /* use rodata elf section for fast lookups of repeating textures */
#ifdef __unix__ /* use rodata elf section for fast lookups of repeating textures */
extern const char start_rodata_address[]; #include "system/linux/elf.h"
extern const char stop_rodata_heuristic[];
asm(".set start_rodata_address, .rodata"); static const char *rodata_start;
asm(".set stop_rodata_heuristic, .data"); /* there's nothing in default linker script to know the size of .rodata */ static const char *rodata_stop;
/* TODO: it might be better to contruct a new table that hashes pointers, not strings, to texture keys */
/* this way every used texture will benefit, no matter the order of commission */
t_texture_key textures_get_key(struct texture_cache *cache, const char *path) { t_texture_key textures_get_key(struct texture_cache *cache, const char *path) {
static const char *last_path = NULL; static const char *last_path = NULL;
static t_texture_key last_texture; static t_texture_key last_texture;
static struct ptr_to_texture {
const void *key;
t_texture_key value;
} *ptr_to_texture;
/* fast path */ if (rodata_stop == NULL)
if (!infer_elf_section_bounds(".rodata", &rodata_start, &rodata_stop))
CRY("Section inference", ".rodata section lookup failed");
/* the fastest path */
if (path == last_path) if (path == last_path)
return last_texture; return last_texture;
else {
/* moderately fast path, by pointer hashing */
const ptrdiff_t texture = hmgeti(ptr_to_texture, path);
if (texture != -1) {
if (path >= rodata_start && path < rodata_stop)
last_path = path;
last_texture = ptr_to_texture[texture].value;
return last_texture;
}
}
/* hash tables are assumed to be stable, so we just return indices */ /* try loading */
ptrdiff_t texture = shgeti(cache->hash, path); last_texture = textures_load(cache, path);
hmput(ptr_to_texture, path, last_texture);
/* load it if it isn't */ if (path >= rodata_start && path < rodata_stop)
if (texture == -1) {
last_texture = textures_load(cache, path);
} else
last_texture = (t_texture_key){ (uint16_t)texture };
if (path >= start_rodata_address && path < stop_rodata_heuristic)
last_path = path; last_path = path;
return last_texture; return last_texture;
@ -400,7 +410,7 @@ t_texture_key textures_get_key(struct texture_cache *cache, const char *path) {
#else #else
t_texture_key textures_get_key(struct texture_cache *cache, const char *path) { t_texture_key textures_get_key(struct texture_cache *cache, const char *path) {
/* hash tables are assumed to be stable, so we just return indices */ /* hash tables are assumed to be stable, so we just return indices */
ptrdiff_t texture = shgeti(cache->hash, path); const ptrdiff_t texture = shgeti(cache->hash, path);
/* load it if it isn't */ /* load it if it isn't */
if (texture == -1) { if (texture == -1) {

View File

@ -1121,7 +1121,7 @@ size_t stbds_hash_bytes(void *p, size_t len, size_t seed)
unsigned char *d = (unsigned char *) p; unsigned char *d = (unsigned char *) p;
if (len == 4) { if (len == 4) {
unsigned int hash = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24); uint32_t hash = (uint32_t)d[0] | ((uint32_t)d[1] << 8) | ((uint32_t)d[2] << 16) | ((uint32_t)d[3] << 24);
#if 0 #if 0
// HASH32-A Bob Jenkin's hash function w/o large constants // HASH32-A Bob Jenkin's hash function w/o large constants
hash ^= seed; hash ^= seed;
@ -1177,8 +1177,8 @@ size_t stbds_hash_bytes(void *p, size_t len, size_t seed)
return (((size_t) hash << 16 << 16) | hash) ^ seed; return (((size_t) hash << 16 << 16) | hash) ^ seed;
} else if (len == 8 && sizeof(size_t) == 8) { } else if (len == 8 && sizeof(size_t) == 8) {
size_t hash = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24); size_t hash = (size_t)d[0] | ((size_t)d[1] << 8) | ((size_t)d[2] << 16) | ((size_t)d[3] << 24);
hash |= (size_t) (d[4] | (d[5] << 8) | (d[6] << 16) | (d[7] << 24)) << 16 << 16; // avoid warning if size_t == 4 hash |= ((size_t)d[4] | ((size_t)d[5] << 8) | ((size_t)d[6] << 16) | ((size_t)d[7] << 24)) << 16 << 16;
hash ^= seed; hash ^= seed;
hash = (~hash) + (hash << 21); hash = (~hash) + (hash << 21);
hash ^= STBDS_ROTATE_RIGHT(hash,24); hash ^= STBDS_ROTATE_RIGHT(hash,24);