From ebe47b452905a160d855e5baf8b9e3f7535768f3 Mon Sep 17 00:00:00 2001 From: Jaromil Date: Fri, 3 Jan 2025 02:52:21 +0100 Subject: [PATCH 1/5] feat: link shared libs on ELF system fix the -L and -l flags to work on GNU/Linux as expected --- src/cjit.c | 7 +- src/linker.c | 448 ++++++++++++++++++++++++++++++++++++++++++++++++ src/linker.h | 14 ++ test/linux.bats | 17 ++ 4 files changed, 482 insertions(+), 4 deletions(-) create mode 100644 src/linker.c create mode 100644 src/linker.h create mode 100644 test/linux.bats diff --git a/src/cjit.c b/src/cjit.c index b6b3d59..0d04d66 100644 --- a/src/cjit.c +++ b/src/cjit.c @@ -51,15 +51,14 @@ static bool cjit_mkdtemp(CJITState *cjit) { char tempDir[MAX_PATH]; #if defined(WINDOWS) char tempPath[MAX_PATH]; - char filename [64]; - snprintf(filename,63,"CJIT-%s",VERSION); + char dirname [64]; + snprintf(dirname,63,"CJIT-%s",VERSION); // Get the temporary path if (GetTempPath(MAX_PATH, tempPath) == 0) { _err("Failed to get temporary path"); return false; } - PathCombine(tempDir, tempPath, filename); - // return already if found existing + cwk_path_join(tempPath,dirname,tempDir,MAX_PATH); DWORD attributes = GetFileAttributes(tempDir); if (attributes == INVALID_FILE_ATTRIBUTES) { // The path does not exist diff --git a/src/linker.c b/src/linker.c new file mode 100644 index 0000000..97a0881 --- /dev/null +++ b/src/linker.c @@ -0,0 +1,448 @@ +/* + * Taken from ELF file handling in TCC + * + * Copyright (c) 2001-2004 Fabrice Bellard + * Copyright (c) 2024-2025 Dyne.org + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// interpret a subset of GNU ldscripts to handle dummy .so files + +#include +#if defined(LINUX) + +#include +#include + +#include +#include +#include +#include + +#define CH_EOF (-1) //end of file +#define LD_TOK_NAME 256 +#define LD_TOK_EOF (-1) + + +#include +#include +#include +#include +#include +#include +#include +#include + +char* read_ld_so_conf_d(const char *directory) { + DIR *dir; + struct dirent *entry; + char path[1024]; + char *result = NULL; + size_t result_len = 0; + + dir = opendir(directory); + if (dir == NULL) { + perror("opendir"); + return NULL; + } + + while ((entry = readdir(dir)) != NULL) { + struct stat st; + snprintf(path, sizeof(path), "%s/%s", directory, entry->d_name); + + // Check if it's a regular file + if (stat(path, &st) == 0 && S_ISREG(st.st_mode)) { + FILE *file = fopen(path, "r"); + if (file == NULL) { + perror("fopen"); + continue; + } + + char line[256]; + while (fgets(line, sizeof(line), file) != NULL) { + // Remove newline character at the end of the line + line[strcspn(line, "\n")] = 0; + // Skip lines that are comments + if (line[0] == '#') continue; + + // Append the line to the result string + size_t line_len = strlen(line); + result = realloc(result, result_len + line_len + 2); // +2 for colon and null terminator + if (result == NULL) { + perror("realloc"); + fclose(file); + closedir(dir); + return NULL; + } + if (result_len == 0) { + strcpy(result, line); + } else { + strcat(result, ":"); + strcat(result, line); + } + result_len += line_len + 1; + } + fclose(file); + } + } + + closedir(dir); + return result; +} + +// int main() { +// char *result = read_ld_so_conf_d("/etc/ld.so.conf.d"); +// if (result != NULL) { +// printf("Colon-separated string: %s\n", result); +// free(result); +// } +// return 0; +// } + +void detect_file_type(const char *filename) { + struct stat st; + if (lstat(filename, &st) == -1) { + perror("lstat"); + return; + } + + if (S_ISLNK(st.st_mode)) { + printf("%s is a symbolic link.\n", filename); + return; + } + + int fd = open(filename, O_RDONLY); + if (fd == -1) { + perror("open"); + return; + } + + unsigned char buffer[512]; + ssize_t bytes_read = read(fd, buffer, sizeof(buffer)); + if (bytes_read == -1) { + perror("read"); + close(fd); + return; + } + + close(fd); + + // Check for plain text ASCII + int is_ascii = 1; + for (ssize_t i = 0; i < bytes_read; i++) { + if (buffer[i] > 127 || (buffer[i] < 32 && buffer[i] != '\n' && buffer[i] != '\r' && buffer[i] != '\t')) { + is_ascii = 0; + break; + } + } + + if (is_ascii) { + printf("%s is a plain text ASCII file.\n", filename); + return; + } + + // Check for ELF binary (common format for shared libraries) + if (bytes_read >= 4 && buffer[0] == 0x7f && buffer[1] == 'E' && buffer[2] == 'L' && buffer[3] == 'F') { + printf("%s is a binary shared library (ELF).\n", filename); + return; + } + + printf("%s is an unknown binary file.\n", filename); +} + +#if defined(TEST_LINKER) +int main(int argc, char *argv[]) { + if (argc != 2) { + fprintf(stderr, "Usage: %s \n", argv[0]); + return EXIT_FAILURE; + } + detect_file_type(argv[1]); + return EXIT_SUCCESS; +} +#endif + +static int ld_inp(LDState *s1) +{ + char b; + if (s1->cc != -1) { + int c = s1->cc; + s1->cc = -1; + return c; + } + if (1 == read(s1->fd, &b, 1)) + return b; + return CH_EOF; +} + +/* return next ld script token */ +static int ld_next(LDState *s1, char *name, int name_size) +{ + int c, d, ch; + char *q; + + redo: + ch = ld_inp(s1); + switch(ch) { + case ' ': + case '\t': + case '\f': + case '\v': + case '\r': + case '\n': + goto redo; + case '/': + ch = ld_inp(s1); + if (ch == '*') { /* comment */ + for (d = 0;; d = ch) { + ch = ld_inp(s1); + if (ch == CH_EOF || (ch == '/' && d == '*')) + break; + } + goto redo; + } else { + q = name; + *q++ = '/'; + goto parse_name; + } + break; + case '\\': + /* case 'a' ... 'z': */ + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + case 'g': + case 'h': + case 'i': + case 'j': + case 'k': + case 'l': + case 'm': + case 'n': + case 'o': + case 'p': + case 'q': + case 'r': + case 's': + case 't': + case 'u': + case 'v': + case 'w': + case 'x': + case 'y': + case 'z': + /* case 'A' ... 'z': */ + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + case 'G': + case 'H': + case 'I': + case 'J': + case 'K': + case 'L': + case 'M': + case 'N': + case 'O': + case 'P': + case 'Q': + case 'R': + case 'S': + case 'T': + case 'U': + case 'V': + case 'W': + case 'X': + case 'Y': + case 'Z': + case '_': + case '.': + case '$': + case '~': + q = name; + parse_name: + for(;;) { + if (!((ch >= 'a' && ch <= 'z') || + (ch >= 'A' && ch <= 'Z') || + (ch >= '0' && ch <= '9') || + strchr("/.-_+=$:\\,~", ch))) + break; + if ((q - name) < name_size - 1) { + *q++ = ch; + } + ch = ld_inp(s1); + } + s1->cc = ch; + *q = '\0'; + c = LD_TOK_NAME; + break; + case CH_EOF: + c = LD_TOK_EOF; + break; + default: + c = ch; + break; + } + return c; +} + +static int ld_add_file(LDState *s1, const char filename[]) { + _err("LD: %s",filename); + return 1; +} + +static int tcc_error_noabort(char *msg) { + _err("ldscript: %s",msg); + return 1; +} + +static int ld_add_file_list(LDState *s1, const char *cmd, int as_needed) +{ + char filename[1024], libname[1024]; + int t, group, nblibs = 0, ret = 0; + char **libs = NULL; + + group = !strcmp(cmd, "GROUP"); + if (!as_needed) + s1->new_undef_sym = 0; + t = ld_next(s1, filename, sizeof(filename)); + if (t != '(') { + ret = tcc_error_noabort("( expected"); + goto lib_parse_error; + } + t = ld_next(s1, filename, sizeof(filename)); + for(;;) { + libname[0] = '\0'; + if (t == LD_TOK_EOF) { + ret = tcc_error_noabort("unexpected end of file"); + goto lib_parse_error; + } else if (t == ')') { + break; + } else if (t == '-') { + t = ld_next(s1, filename, sizeof(filename)); + if ((t != LD_TOK_NAME) || (filename[0] != 'l')) { + ret = tcc_error_noabort("library name expected"); + goto lib_parse_error; + } + pstrcpy(libname, sizeof libname, &filename[1]); + if (s1->static_link) { + snprintf(filename, sizeof filename, "lib%s.a", libname); + } else { + snprintf(filename, sizeof filename, "lib%s.so", libname); + } + } else if (t != LD_TOK_NAME) { + ret = tcc_error_noabort("filename expected"); + goto lib_parse_error; + } + if (!strcmp(filename, "AS_NEEDED")) { + ret = ld_add_file_list(s1, cmd, 1); + if (ret) + goto lib_parse_error; + } else { + /* TODO: Implement AS_NEEDED support. */ + /* DT_NEEDED is not used any more so ignore as_needed */ + if (1 || !as_needed) { + ret = ld_add_file(s1, filename); + if (ret) + goto lib_parse_error; + if (group) { + /* Add the filename *and* the libname to avoid future conversions */ + dynarray_add(&libs, &nblibs, tcc_strdup(filename)); + if (libname[0] != '\0') + dynarray_add(&libs, &nblibs, tcc_strdup(libname)); + } + } + } + t = ld_next(s1, filename, sizeof(filename)); + if (t == ',') { + t = ld_next(s1, filename, sizeof(filename)); + } + } + if (group && !as_needed) { + while (s1->new_undef_sym) { + int i; + s1->new_undef_sym = 0; + for (i = 0; i < nblibs; i ++) + ld_add_file(s1, libs[i]); + } + } +lib_parse_error: + dynarray_reset(&libs, &nblibs); + return ret; +} + +// fd = open(filename, O_RDONLY | O_BINARY); +int cjit_load_ldscript(LDState *s1, char *path) { + char cmd[64]; + char filename[1024]; + int t, ret; + int fd = open(path, O_RDONLY | O_BINARY); + + s1->fd = fd; + s1->cc = -1; + for(;;) { + t = ld_next(s1, cmd, sizeof(cmd)); + if (t == LD_TOK_EOF) { + close(fd); + return 0; + } + else if (t != LD_TOK_NAME) { + close(fd); + return -1; + } + if (!strcmp(cmd, "INPUT") || + !strcmp(cmd, "GROUP")) { + ret = ld_add_file_list(s1, cmd, 0); + if (ret) { + close(fd); + return ret; + } + } else if (!strcmp(cmd, "OUTPUT_FORMAT") || + !strcmp(cmd, "TARGET")) { + /* ignore some commands */ + t = ld_next(s1, cmd, sizeof(cmd)); + if (t != '(') { + _err("%s: ( expected while parsing %s", + __func__,path); + close(fd); + return 0; + } + for(;;) { + t = ld_next(s1, filename, sizeof(filename)); + if (t == LD_TOK_EOF) { + _err("%s: unexpected end of file in %s", + __func__,path); + close(fd); + return 0; + } else if (t == ')') { + break; + } + } + } else { + close(fd); + return -1; + } + } + close(fd); + return 0; +} + +#endif // only GNU/Linux platform diff --git a/src/linker.h b/src/linker.h new file mode 100644 index 0000000..e49595b --- /dev/null +++ b/src/linker.h @@ -0,0 +1,14 @@ +#ifndef __LDSCRIPT_H__ +#define __LDSCRIPT_H__ + +struct LDState { + int cc; + int fd; + int new_undef_sym; + int static_link; +}; +typedef struct LDState LDState; + +int cjit_load_ldscript(LDState *s1, char *path); + +#endif diff --git a/test/linux.bats b/test/linux.bats new file mode 100644 index 0000000..4d1d6ed --- /dev/null +++ b/test/linux.bats @@ -0,0 +1,17 @@ +load bats_setup + +@test "linker resolution of simple gnu ld scripts" { + cat << EOF > ldscript_test.c +#include +int main(int argc, char **argv) { + LDState s1; + int res; + res = cjit_load_ldscript(&s1,"/usr/lib/x86_64-linux-gnu/libm.so"); + return(res); +} +EOF + run ${CJIT} -DVERSION=debug --verb ldscript_test.c \ + -I ${R}/src ${R}/src/cjit.c ${R}/src/linker.c \ + ${R}/lib/tinycc/libtcc.a + assert_success +} From fe6ab338b1461546adbae33c84d68f00c8296927 Mon Sep 17 00:00:00 2001 From: Jaromil Date: Fri, 3 Jan 2025 04:16:21 +0100 Subject: [PATCH 2/5] feat: dynamic arrays from libxutils in cjit core using the XArray class to handle some internal dynamic arrays listing configured sources, libs and library paths to override internal tcc handling which seems broken esp on ELF linkage --- build/init.mk | 2 +- src/array.c | 542 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/array.h | 101 ++++++++++ src/cjit.c | 98 ++++++--- src/cjit.h | 5 + 5 files changed, 720 insertions(+), 28 deletions(-) create mode 100644 src/array.c create mode 100644 src/array.h diff --git a/build/init.mk b/build/init.mk index 75d33db..aeb1540 100644 --- a/build/init.mk +++ b/build/init.mk @@ -17,7 +17,7 @@ cflags := ${CFLAGS} ${cflags_includes} SOURCES := src/file.o src/cjit.o \ src/main.o src/assets.o \ - src/cwalk.o \ + src/cwalk.o src/array.o \ src/muntar.o src/tinflate.o src/tinfgzip.o \ src/embed_libtcc1.a.o src/embed_include.o #src/embed_source.o diff --git a/src/array.c b/src/array.c new file mode 100644 index 0000000..cb2a290 --- /dev/null +++ b/src/array.c @@ -0,0 +1,542 @@ +/*! + * @file libxutils/src/data/array.c + * + * This source is part of "libxutils" project + * 2015-2020 Sun Dro (s.kalatoz@gmail.com) + * + * @brief Dynamically allocated data holder + * with some sorting and search algorithms. + */ + +#include +#include "array.h" + +xarray_data_t *XArray_NewData(void *pData, size_t nSize, uint32_t nKey) +{ + xarray_data_t *pNewData = (xarray_data_t*)malloc(sizeof(xarray_data_t)); + if (pNewData == NULL) return NULL; + + if (pData != NULL && nSize > 0) + { + pNewData->pData = malloc(nSize + 1); + if (pNewData->pData == NULL) + { + free(pNewData); + return NULL; + } + + memcpy(pNewData->pData, pData, nSize); + pNewData->nSize = nSize; + } + else + { + pNewData->pData = pData; + pNewData->nSize = 0; + } + + pNewData->nKey = nKey; + return pNewData; +} + +void XArray_FreeData(xarray_data_t *pArrData) +{ + if (pArrData != NULL) + { + if (pArrData->pData && + pArrData->nSize > 0) + free(pArrData->pData); + + free(pArrData); + } +} + +void XArray_ClearData(xarray_t *pArr, xarray_data_t *pArrData) +{ + if (pArr != NULL && + pArrData != NULL && + pArr->clearCb != NULL) + { + pArr->clearCb(pArrData); + pArrData->pData = NULL; + pArrData->nSize = 0; + } + + XArray_FreeData(pArrData); +} + +void* XArray_Init(xarray_t *pArr, size_t nSize, uint8_t nFixed) +{ + pArr->eStatus = XARRAY_STATUS_EMPTY; + pArr->clearCb = NULL; + pArr->pData = NULL; + pArr->nSize = nSize; + pArr->nFixed = nFixed; + pArr->nAlloc = 0; + pArr->nUsed = 0; + + if (nSize) + { + pArr->pData = (xarray_data_t**)malloc(nSize * sizeof(xarray_data_t*)); + if (pArr->pData == NULL) return NULL; + } + + size_t i; + for (i = 0; i < nSize; i++) + pArr->pData[i] = NULL; + + return pArr->pData; +} + +xarray_t* XArray_New(size_t nSize, uint8_t nFixed) +{ + xarray_t *pArr = (xarray_t*)malloc(sizeof(xarray_t)); + if (pArr == NULL) return NULL; + + if (XArray_Init(pArr, nSize, nFixed) == NULL && nSize) + { + free(pArr); + return NULL; + } + + pArr->nAlloc = 1; + return pArr; +} + +void XArray_Clear(xarray_t *pArr) +{ + if (pArr->pData != NULL) + { + size_t i; + for (i = 0; i < pArr->nSize; i++) + { + XArray_ClearData(pArr, pArr->pData[i]); + pArr->pData[i] = NULL; + } + } + + pArr->eStatus = XARRAY_STATUS_EMPTY; + pArr->nUsed = 0; +} + +void XArray_Destroy(xarray_t *pArr) +{ + XArray_Clear(pArr); + if (pArr->pData != NULL) + { + free(pArr->pData); + pArr->pData = NULL; + } + + pArr->nSize = 0; + pArr->nFixed = 0; + + if (pArr->nAlloc) + free(pArr); +} + +void XArray_Free(xarray_t **ppArr) +{ + if (ppArr == NULL || + *ppArr == NULL) return; + + xarray_t *pArr = *ppArr; + XArray_Destroy(pArr); + *ppArr = NULL; +} + +uint8_t XArray_Contains(xarray_t *pArr, size_t nIndex) +{ + if (pArr == NULL || nIndex >= pArr->nSize) return 0; + return pArr->pData[nIndex] != NULL ? 1 : 0; +} + +size_t XArray_Realloc(xarray_t *pArr) +{ + if (pArr->nFixed) return pArr->nSize; + size_t nSize = 0, nUsed = pArr->nUsed; + float fQuotient = (float)nUsed / (float)pArr->nSize; + + if (nUsed && nUsed == pArr->nSize) nSize = pArr->nSize * 2; + else if (nUsed && fQuotient < 0.25) nSize = pArr->nSize / 2; + + if (nSize) + { + xarray_data_t **pData = (xarray_data_t**)malloc(sizeof(xarray_data_t*) * nSize); + if (pData == NULL) + { + pArr->eStatus = XARRAY_STATUS_NO_MEMORY; + return 0; + } + + size_t nCopySize = sizeof(xarray_data_t*) * pArr->nSize; + memcpy(pData, pArr->pData, nCopySize); + + free(pArr->pData); + pArr->pData = pData; + pArr->nSize = nSize; + + size_t i; + for (i = nUsed; i < nSize; i++) + pArr->pData[i] = NULL; + } + + return pArr->nSize; +} + +size_t XArray_CheckSpace(xarray_t *pArr) +{ + if (pArr == NULL) return 0; + + if (pArr->pData == NULL) + { + uint8_t nAlloc = pArr->nAlloc; + xarray_clear_cb_t clearCb = pArr->clearCb; + XArray_Init(pArr, XARRAY_INITIAL_SIZE, 0); + pArr->clearCb = clearCb; + pArr->nAlloc = nAlloc; + } + else if (pArr->nUsed >= pArr->nSize) + return XArray_Realloc(pArr); + + return pArr->pData == NULL ? 0 : 1; +} + +int XArray_Add(xarray_t *pArr, xarray_data_t *pNewData) +{ + if (!XArray_CheckSpace(pArr)) + { + XArray_ClearData(pArr, pNewData); + return XARRAY_FAILURE; + } + + pArr->pData[pArr->nUsed++] = pNewData; + return (int)pArr->nUsed - 1; +} + +int XArray_AddData(xarray_t *pArr, void *pData, size_t nSize) +{ + if (pArr == NULL) return XARRAY_FAILURE; + xarray_data_t *pNewData = XArray_NewData(pData, nSize, 0); + + if (pNewData == NULL) + { + pArr->eStatus = XARRAY_STATUS_NO_MEMORY; + return XARRAY_FAILURE; + } + + return XArray_Add(pArr, pNewData); +} + +int XArray_PushData(xarray_t *pArr, void *pData, size_t nSize) +{ + xarray_data_t *pNewData = XArray_NewData(pData, 0, 0); + if (pNewData == NULL) + { + pArr->eStatus = XARRAY_STATUS_NO_MEMORY; + return XARRAY_FAILURE; + } + + pNewData->nSize = nSize; + return XArray_Add(pArr, pNewData); +} + +int XArray_AddDataKey(xarray_t *pArr, void *pData, size_t nSize, uint32_t nKey) +{ + xarray_data_t *pNewData = XArray_NewData(pData, nSize, nKey); + + if (pNewData == NULL) + { + pArr->eStatus = XARRAY_STATUS_NO_MEMORY; + return XARRAY_FAILURE; + } + + return XArray_Add(pArr, pNewData); +} + +xarray_data_t* XArray_Get(xarray_t *pArr, size_t nIndex) +{ + if (nIndex >= pArr->nSize) return NULL; + return pArr->pData[nIndex]; +} + +void* XArray_GetData(xarray_t *pArr, size_t nIndex) +{ + if (nIndex >= pArr->nSize) return NULL; + xarray_data_t *pArrData = pArr->pData[nIndex]; + return pArrData ? pArrData->pData : NULL; +} + +void* XArray_GetDataOr(xarray_t *pArr, size_t nIndex, void *pRet) +{ + if (nIndex >= pArr->nSize) return pRet; + xarray_data_t *pArrData = pArr->pData[nIndex]; + return pArrData ? pArrData->pData : pRet; +} + +size_t XArray_GetSize(xarray_t *pArr, size_t nIndex) +{ + if (nIndex >= pArr->nSize) return 0; + xarray_data_t *pArrData = pArr->pData[nIndex]; + return pArrData ? pArrData->nSize : 0; +} + +uint32_t XArray_GetKey(xarray_t *pArr, size_t nIndex) +{ + if (nIndex >= pArr->nSize) return 0; + xarray_data_t *pArrData = pArr->pData[nIndex]; + return pArrData ? pArrData->nKey : 0; +} + +xarray_data_t* XArray_Remove(xarray_t *pArr, size_t nIndex) +{ + xarray_data_t *pData = XArray_Get(pArr, nIndex); + if (pData == NULL) return NULL; + + size_t i; + for (i = nIndex; i < pArr->nUsed; i++) + { + if ((i + 1) >= pArr->nUsed) break; + pArr->pData[i] = pArr->pData[i+1]; + } + + pArr->pData[--pArr->nUsed] = NULL; + XArray_Realloc(pArr); + return pData; +} + +void XArray_Delete(xarray_t *pArr, size_t nIndex) +{ + xarray_data_t *pData = XArray_Get(pArr, nIndex); + if (pData != NULL) XArray_ClearData(pArr, pData); +} + +xarray_data_t* XArray_Set(xarray_t *pArr, size_t nIndex, xarray_data_t *pNewData) +{ + xarray_data_t *pOldData = NULL; + if (nIndex < pArr->nSize) + { + pOldData = pArr->pData[nIndex]; + pArr->pData[nIndex] = pNewData; + } + + return pOldData; +} + +xarray_data_t* XArray_SetData(xarray_t *pArr, size_t nIndex, void *pData, size_t nSize) +{ + xarray_data_t *pNewData = XArray_NewData(pData, nSize, 0); + if (pNewData == NULL) + { + pArr->eStatus = XARRAY_STATUS_NO_MEMORY; + return NULL; + } + + xarray_data_t *pOldData = XArray_Set(pArr, nIndex, pNewData); + return pOldData; +} + +xarray_data_t* XArray_Insert(xarray_t *pArr, size_t nIndex, xarray_data_t *pData) +{ + if (!XArray_CheckSpace(pArr)) return NULL; + + xarray_data_t *pOldData = XArray_Set(pArr, nIndex, pData); + if (pOldData == NULL) return NULL; + + size_t i, nNextIndex = nIndex + 1; + + for (i = nNextIndex; i < pArr->nUsed; i++) + pOldData = XArray_Set(pArr, i, pOldData); + + XArray_Add(pArr, pOldData); + return pArr->pData[nNextIndex]; +} + +xarray_data_t* XArray_InsertData(xarray_t *pArr, size_t nIndex, void *pData, size_t nSize) +{ + if (!XArray_CheckSpace(pArr)) return NULL; + + xarray_data_t *pNewData = XArray_NewData(pData, nSize, 0); + if (pNewData == NULL) + { + pArr->eStatus = XARRAY_STATUS_NO_MEMORY; + return NULL; + } + + return XArray_Insert(pArr, nIndex, pNewData); +} + +void XArray_Swap(xarray_t *pArr, size_t nIndex1, size_t nIndex2) +{ + if (nIndex1 >= pArr->nUsed || + nIndex2 >= pArr->nUsed) return; + + xarray_data_t *pData1 = pArr->pData[nIndex1]; + pArr->pData[nIndex1] = pArr->pData[nIndex2]; + pArr->pData[nIndex2] = pData1; +} + +static int XArray_CompareSize(const void *pData1, const void *pData2, void *pCtx) +{ + (void)pCtx; + xarray_data_t *pFirst = (xarray_data_t*)pData1; + xarray_data_t *pSecond = (xarray_data_t*)pData2; + return (int)pFirst->nSize - (int)pSecond->nSize; +} + +static int XArray_CompareKey(const void *pData1, const void *pData2, void *pCtx) +{ + (void)pCtx; + xarray_data_t *pFirst = (xarray_data_t*)pData1; + xarray_data_t *pSecond = (xarray_data_t*)pData2; + return (int)pFirst->nKey - (int)pSecond->nKey; +} + +int XArray_Partitioning(xarray_t *pArr, xarray_comparator_t compare, void *pCtx, int nStart, int nFinish) +{ + int nPivot = nStart; + while(1) + { + while (compare((void*)pArr->pData[nStart], (void*)pArr->pData[nPivot], pCtx) < 0) nStart++; + while (compare((void*)pArr->pData[nFinish], (void*)pArr->pData[nPivot], pCtx) > 0) nFinish--; + if (!compare((void*)pArr->pData[nStart], (void*)pArr->pData[nFinish], pCtx)) nFinish--; + if (nStart >= nFinish) return nStart; + XArray_Swap(pArr, nStart, nFinish); + } + + return nStart; +} + +void XArray_QuickSort(xarray_t *pArr, xarray_comparator_t compare, void *pCtx, int nStart, int nFinish) +{ + if (nStart < nFinish) + { + int nPartitioning = XArray_Partitioning(pArr, compare, pCtx, nStart, nFinish); + XArray_QuickSort(pArr, compare, pCtx, nStart, nPartitioning); + XArray_QuickSort(pArr, compare, pCtx, nPartitioning+1, nFinish); + } +} + +void XArray_Sort(xarray_t *pArr, xarray_comparator_t compare, void *pCtx) +{ + if (pArr == NULL || !pArr->nUsed) return; + XArray_QuickSort(pArr, compare, pCtx, 0, (int)pArr->nUsed-1); +} + +void XArray_SortBy(xarray_t *pArr, int nSortBy) +{ + if (nSortBy == XARRAY_SORTBY_SIZE) + XArray_Sort(pArr, XArray_CompareSize, NULL); + else if (nSortBy == XARRAY_SORTBY_KEY) + XArray_Sort(pArr, XArray_CompareKey, NULL); +} + +void XArray_BubbleSort(xarray_t *pArr, xarray_comparator_t compare, void *pCtx) +{ + if (pArr == NULL || !pArr->nUsed) return; + size_t i, j; + + for (i = 0; i < pArr->nUsed-1; i++) + { + for (j = 0 ; j < pArr->nUsed-i-1; j++) + { + if (compare((void*)pArr->pData[j], (void*)pArr->pData[j+1], pCtx)) + { + xarray_data_t *pData = pArr->pData[j]; + pArr->pData[j] = pArr->pData[j+1]; + pArr->pData[j+1] = pData; + } + } + } +} + +int XArray_LinearSearch(xarray_t *pArr, uint32_t nKey) +{ + if (pArr == NULL || !pArr->nUsed) return XARRAY_FAILURE; + size_t i = 0; + + for (i = 0; i < pArr->nUsed; i++) + { + xarray_data_t *pData = pArr->pData[i]; + if (nKey == pData->nKey) return (int)i; + } + + return XARRAY_FAILURE; +} + +int XArray_SentinelSearch(xarray_t *pArr, uint32_t nKey) +{ + if (pArr == NULL || !pArr->nUsed) return XARRAY_FAILURE; + int i, nRet = 0, nLast = (int)pArr->nUsed - 1; + + xarray_data_t *pLast = pArr->pData[nLast]; + if (pLast->nKey == nKey) return nLast; + + xarray_data_t term = {.nKey = nKey, .nSize = 0, .pData = NULL}; + pArr->pData[nLast] = &term; + + for (i = 0;; i++) + { + xarray_data_t *pData = pArr->pData[i]; + if (nKey == pData->nKey) + { + pArr->pData[nLast] = pLast; + nRet = (i < nLast) ? i : -1; + break; + } + } + + return nRet; +} + +int XArray_DoubleSearch(xarray_t *pArr, uint32_t nKey) +{ + if (pArr == NULL || !pArr->nUsed) return XARRAY_FAILURE; + int nFront = 0, nBack = (int)pArr->nUsed - 1; + + while (nFront <= nBack) + { + xarray_data_t *pData = pArr->pData[nFront]; + if (nKey == pData->nKey) return nFront; + + pData = pArr->pData[nBack]; + if (nKey == pData->nKey) return nBack; + + nFront++; + nBack--; + } + + return XARRAY_FAILURE; +} + +int XArray_BinarySearch(xarray_t *pArr, uint32_t nKey) +{ + if (pArr == NULL || !pArr->nUsed) return XARRAY_FAILURE; + int nLeft = 0, nRight = (int)pArr->nUsed - 1; + + xarray_data_t *pData = pArr->pData[nLeft]; + if (pData->nKey == nKey) return nLeft; + + while (nLeft <= nRight) + { + int nMiddle = nLeft + (nRight - nLeft) / 2; + pData = pArr->pData[nMiddle]; + + if (pData->nKey < nKey) nLeft = nMiddle + 1; + else if (pData->nKey == nKey) return nMiddle; + else nRight = nMiddle - 1; + } + + return XARRAY_FAILURE; +} + +size_t XArray_Used(xarray_t *pArr) +{ + if (pArr == NULL) return 0; + return pArr->nUsed; +} + +size_t XArray_Size(xarray_t *pArr) +{ + if (pArr == NULL) return 0; + return pArr->nSize; +} diff --git a/src/array.h b/src/array.h new file mode 100644 index 0000000..3cdb7e4 --- /dev/null +++ b/src/array.h @@ -0,0 +1,101 @@ +/*! + * @file libxutils/src/data/array.h + * + * This source is part of "libxutils" project + * 2015-2020 Sun Dro (s.kalatoz@gmail.com) + * + * @brief Dynamically allocated data holder + * with some sorting and search algorithms. + */ + +#ifndef __XUTILS_XARRAY_H__ +#define __XUTILS_XARRAY_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#define XARRAY_SUCCESS 0 +#define XARRAY_FAILURE -1 + +#define XARRAY_INITIAL_SIZE 8 +#define XARRAY_SORTBY_SIZE 1 +#define XARRAY_SORTBY_KEY 0 + +typedef enum { + XARRAY_STATUS_OK = (uint8_t)0, + XARRAY_STATUS_EMPTY, + XARRAY_STATUS_NO_MEMORY +} xarray_status_t; + +typedef struct XArrayData { + void* pData; + size_t nSize; + uint32_t nKey; +} xarray_data_t; + +typedef int(*xarray_comparator_t)(const void*, const void*, void*); +typedef void(*xarray_clear_cb_t)(xarray_data_t *pArrData); + +typedef struct XArray_ { + xarray_data_t** pData; + xarray_clear_cb_t clearCb; + xarray_status_t eStatus; + uint8_t nFixed; + uint8_t nAlloc; + size_t nSize; + size_t nUsed; +} xarray_t; + +xarray_data_t *XArray_NewData(void *pData, size_t nSize, uint32_t nKey); +void XArray_FreeData(xarray_data_t *pArrData); +void XArray_ClearData(xarray_t *pArr, xarray_data_t *pArrData); + +xarray_t* XArray_New(size_t nSize, uint8_t nFixed); +void* XArray_Init(xarray_t *pArr, size_t nSize, uint8_t nFixed); +size_t XArray_Realloc(xarray_t *pArr); +void XArray_Destroy(xarray_t *pArr); +void XArray_Clear(xarray_t *pArr); +void XArray_Free(xarray_t **ppArr); + +int XArray_Add(xarray_t *pArr, xarray_data_t *pNewData); +int XArray_AddData(xarray_t *pArr, void* pData, size_t nSize); +int XArray_PushData(xarray_t *pArr, void *pData, size_t nSize); +int XArray_AddDataKey(xarray_t *pArr, void* pData, size_t nSize, uint32_t nKey); +void* XArray_GetDataOr(xarray_t *pArr, size_t nIndex, void *pRet); +void* XArray_GetData(xarray_t *pArr, size_t nIndex); +size_t XArray_GetSize(xarray_t *pArr, size_t nIndex); +uint32_t XArray_GetKey(xarray_t *pArr, size_t nIndex); +uint8_t XArray_Contains(xarray_t *pArr, size_t nIndex); + +xarray_data_t* XArray_Remove(xarray_t *pArr, size_t nIndex); +void XArray_Delete(xarray_t *pArr, size_t nIndex); +void XArray_Swap(xarray_t *pArr, size_t nIndex1, size_t nIndex2); + +void XArray_Sort(xarray_t *pArr, xarray_comparator_t compare, void *pCtx); +void XArray_BubbleSort(xarray_t *pArr, xarray_comparator_t compare, void *pCtx); +void XArray_QuickSort(xarray_t *pArr, xarray_comparator_t compare, void *pCtx, int nStart, int nFinish); +void XArray_SortBy(xarray_t *pArr, int nSortBy); + +int XArray_SentinelSearch(xarray_t *pArr, uint32_t nKey); +int XArray_LinearSearch(xarray_t *pArr, uint32_t nKey); +int XArray_DoubleSearch(xarray_t *pArr, uint32_t nKey); +int XArray_BinarySearch(xarray_t *pArr, uint32_t nKey); + +xarray_data_t* XArray_Get(xarray_t *pArr, size_t nIndex); +xarray_data_t* XArray_Set(xarray_t *pArr, size_t nIndex, xarray_data_t *pNewData); +xarray_data_t* XArray_Insert(xarray_t *pArr, size_t nIndex, xarray_data_t *pData); +xarray_data_t* XArray_SetData(xarray_t *pArr, size_t nIndex, void *pData, size_t nSize); +xarray_data_t* XArray_InsertData(xarray_t *pArr, size_t nIndex, void *pData, size_t nSize); + +size_t XArray_Used(xarray_t *pArr); +size_t XArray_Size(xarray_t *pArr); + +#ifdef __cplusplus +} +#endif + +#endif /* __XUTILS_XARRAY_H__ */ diff --git a/src/cjit.c b/src/cjit.c index 0d04d66..3ff2f54 100644 --- a/src/cjit.c +++ b/src/cjit.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -38,6 +39,8 @@ #define tcc(cjit) (TCCState*)cjit->TCC #define setup if(!cjit->done_setup)cjit_setup(cjit) #define debug(fmt,par) if(cjit->verbose)_err(fmt,par) +#define add(buf,s) if(s)XArray_AddData((xarray_t*)cjit->buf,(char*)s,strlen(s)+1); else _err("!!! NULL var added to array: %s","buf") + // declared at bottom void _out(const char *fmt, ...); void _err(const char *fmt, ...); @@ -135,6 +138,10 @@ CJITState* cjit_new() { } // error handler callback for TCC tcc_set_error_func(tcc(cjit), stderr, cjit_tcc_handle_error); + // initialize internal arrays + cjit->sources = (void*)XArray_New(2, 0); + cjit->libs = (void*)XArray_New(2, 0); + cjit->libpaths = (void*)XArray_New(2, 0); return(cjit); } @@ -154,7 +161,7 @@ static bool cjit_setup(CJITState *cjit) { _err("CFLAGS: %s",extra_cflags); tcc_set_options(tcc(cjit), extra_cflags); } -#if defined(_WIN32) +#if defined(WINDOWS) // add symbols for windows compatibility tcc_add_symbol(tcc(cjit), "usleep", &win_compat_usleep); tcc_add_symbol(tcc(cjit), "getline", &win_compat_getline); @@ -164,35 +171,42 @@ static bool cjit_setup(CJITState *cjit) { tcc_define_symbol(tcc(cjit),"SDL_MAIN_HANDLED",NULL); // where is libtcc1.a found - tcc_add_library_path(tcc(cjit), cjit->tmpdir); - - // tcc_set_lib_path(TCC,tmpdir); // this overrides all? - + // add(libpaths,cjit->tmpdir); + // tinyCC needs libtcc1.a in library path (not added as file) + tcc_add_library_path(tcc(cjit),cjit->tmpdir); + { // search libs also in current dir + char pwd[MAX_PATH]; + // Get the current working directory + if(getcwd(pwd, MAX_PATH)) + add(libpaths,pwd); + } tcc_add_sysinclude_path(tcc(cjit), cjit->tmpdir); tcc_add_sysinclude_path(tcc(cjit), "."); - tcc_add_sysinclude_path(tcc(cjit), "include"); - tcc_add_library_path(tcc(cjit), "."); + tcc_add_sysinclude_path(tcc(cjit), "include"); // TODO: check if exists -#if defined(_WIN32) +#if defined(WINDOWS) { - // windows system32 libraries - //tcc_add_library_path(TCC, "C:\\Windows\\System32") - // 64bit + size_t plen; + char *tpath; + // TODO: support WIN32 here: "C:\\Windows\\System32" + add(libpaths,"C:\\Windows\\SysWOW64"); tcc_add_library_path(tcc(cjit), "C:\\Windows\\SysWOW64"); // tinycc win32 headers - char *tpath = malloc(strlen(cjit->tmpdir)+32); - strcpy(tpath,cjit->tmpdir); - strcat(tpath,"/tinycc_win32/winapi"); + plen = strlen(cjit->tmpdir)+strlen("/tinycc_win32/winapi")+8; + tpath = malloc(plen); + cwk_path_join(cjit->tmpdir,"/tinycc_win32/winapi",tpath,plen); tcc_add_sysinclude_path(tcc(cjit), tpath); free(tpath); // windows SDK headers char *sdkpath = malloc(512); if( get_winsdkpath(sdkpath,511) ) { - int pathend = strlen(sdkpath); - strcpy(&sdkpath[pathend],"\\um"); // um/GL - tcc_add_sysinclude_path(tcc(cjit), sdkpath); - strcpy(&sdkpath[pathend],"\\shared"); // winapifamili.h etc. - tcc_add_sysinclude_path(tcc(cjit), sdkpath); + plen = strlen(sdkpath)+16; + tpath = malloc(plen); + cwk_path_join(sdkpath,"/um",tpath,plen); // um/GL + tcc_add_sysinclude_path(tcc(cjit), tpath); + cwk_path_join(sdkpath,"/shared",tpath,plen); // winapifamili.h etc. + tcc_add_sysinclude_path(tcc(cjit), tpath); + free(tpath); } free(sdkpath); } @@ -233,6 +247,29 @@ bool cjit_status(CJITState *cjit) { #if !(defined TCC_TARGET_PE || defined TCC_TARGET_MACHO) _err("ELF interpreter: %s",CONFIG_TCC_ELFINTERP); #endif + setup; + { + int i; + size_t used; + used= XArray_Used(cjit->sources); + if(used) { + _err("Sources (%u)",used); + for(i=0;isources,i)); + } + used = XArray_Used(cjit->libpaths); + if(used) { + _err("Library paths (%u)",used); + for(i=0;ilibpaths,i)); + } + used = XArray_Used(cjit->libs); + if(used) { + _err("Libraries (%u)",used); + for(int i=0;ilibs,i)); + } + } return true; } @@ -339,14 +376,16 @@ bool cjit_add_source(CJITState *cjit, const char *path) { fread(contents+spath_len, 1, length, file); contents[length+spath_len] = 0x0; fclose(file); - size_t dirname; - cwk_path_get_dirname(path,&dirname); - if(dirname) { - char *tmp = malloc(dirname+1); - strncpy(tmp,path,dirname); - tmp[dirname] = 0x0; - tcc_add_include_path(tcc(cjit),tmp); - free(tmp); + { // if inside a dir then add dir to includes too + size_t dirname; + cwk_path_get_dirname(path,&dirname); + if(dirname) { + char *tmp = malloc(dirname+1); + strncpy(tmp,path,dirname); + tmp[dirname] = 0x0; + tcc_add_include_path(tcc(cjit),tmp); + free(tmp); + } } tcc_compile_string(tcc(cjit),contents); free(contents); @@ -520,6 +559,9 @@ void cjit_free(CJITState *cjit) { if(cjit->entry) free(cjit->entry); if(cjit->output_filename) free(cjit->output_filename); if(cjit->TCC) tcc_delete(tcc(cjit)); + XArray_Free((xarray_t**)&cjit->sources); + XArray_Free((xarray_t**)&cjit->libs); + XArray_Free((xarray_t**)&cjit->libpaths); free(cjit); } @@ -542,11 +584,13 @@ void cjit_add_include_path(CJITState *cjit, const char *path) { // TODO: temporary, to be reimplemented in linker.c void cjit_add_library_path(CJITState *cjit, const char *path) { tcc_add_library_path(tcc(cjit), path); + add(libpaths,path); debug("+L %s",path); } // TODO: temporary, to be reimplemented in linker.c void cjit_add_library(CJITState *cjit, const char *path) { tcc_add_library(tcc(cjit), path); + add(libs,path); debug("+l %s",path); } void cjit_set_tcc_options(CJITState *cjit, const char *opts) { diff --git a/src/cjit.h b/src/cjit.h index 3d0eeec..04299ed 100644 --- a/src/cjit.h +++ b/src/cjit.h @@ -42,6 +42,11 @@ struct CJITState { char *output_filename; // output in case of compilation mode bool done_setup; bool done_exec; + // INTERNAL + // sources and libs used and paths to libs + void *sources; + void *libs; + void *libpaths; }; typedef struct CJITState CJITState; From fc2f600fef332b4ba6dcc64be4bb83acdd0e3b7b Mon Sep 17 00:00:00 2001 From: Jaromil Date: Fri, 3 Jan 2025 06:07:19 +0100 Subject: [PATCH 3/5] fix: elf library parse /etc/ld.so.conf.d --- build/linux.mk | 2 + src/cjit.c | 18 +++++++- src/{linker.c => elflinker.c} | 82 ++++++++++++----------------------- src/{linker.h => elflinker.h} | 0 4 files changed, 45 insertions(+), 57 deletions(-) rename src/{linker.c => elflinker.c} (86%) rename src/{linker.h => elflinker.h} (100%) diff --git a/build/linux.mk b/build/linux.mk index 987bc06..b34a3f5 100644 --- a/build/linux.mk +++ b/build/linux.mk @@ -5,10 +5,12 @@ cc := gcc cflags += -DLIBC_GNU -D_GNU_SOURCE cflags += -DKILO_SUPPORTED cflags += -DCJIT_BUILD_LINUX +SOURCES += src/elflinker.o all: embed-posix cjit tinycc_config += --with-libgcc +$(info Ignore any error about sestatus below) ifeq ($(shell sestatus | awk -F': *' '/SELinux status:/ {print $2}'), enabled) tinycc_config += --with-selinux endif diff --git a/src/cjit.c b/src/cjit.c index 3ff2f54..0f15b1a 100644 --- a/src/cjit.c +++ b/src/cjit.c @@ -39,7 +39,7 @@ #define tcc(cjit) (TCCState*)cjit->TCC #define setup if(!cjit->done_setup)cjit_setup(cjit) #define debug(fmt,par) if(cjit->verbose)_err(fmt,par) -#define add(buf,s) if(s)XArray_AddData((xarray_t*)cjit->buf,(char*)s,strlen(s)+1); else _err("!!! NULL var added to array: %s","buf") +#define add(buf,s) if(s!=NULL)XArray_AddData((xarray_t*)cjit->buf,(char*)s,strlen(s)+1); else _err("!!! NULL var added to array: %s","buf") // declared at bottom void _out(const char *fmt, ...); @@ -177,8 +177,9 @@ static bool cjit_setup(CJITState *cjit) { { // search libs also in current dir char pwd[MAX_PATH]; // Get the current working directory - if(getcwd(pwd, MAX_PATH)) + if(getcwd(pwd, MAX_PATH)) { add(libpaths,pwd); + } } tcc_add_sysinclude_path(tcc(cjit), cjit->tmpdir); tcc_add_sysinclude_path(tcc(cjit), "."); @@ -211,6 +212,19 @@ static bool cjit_setup(CJITState *cjit) { free(sdkpath); } #endif + +#if defined(LINUX) + { + xarray_t ldsoconf; + XArray_Init(&ldsoconf,3,0); + read_ldsoconf(&ldsoconf,"/etc/ld.so.conf.d"); + int len = XArray_Used(&ldsoconf); + for(int i=0;idone_setup = true; return(true); } diff --git a/src/linker.c b/src/elflinker.c similarity index 86% rename from src/linker.c rename to src/elflinker.c index 97a0881..d1f478d 100644 --- a/src/linker.c +++ b/src/elflinker.c @@ -23,22 +23,19 @@ #include #if defined(LINUX) - +#define MAX_PATH 512 #include -#include - -#include -#include -#include -#include +#include +#include +#include #define CH_EOF (-1) //end of file #define LD_TOK_NAME 256 #define LD_TOK_EOF (-1) - #include #include +#include #include #include #include @@ -46,72 +43,47 @@ #include #include -char* read_ld_so_conf_d(const char *directory) { +// tinyCC internals used here +extern void dynarray_add(void *ptab, int *nb_ptr, void *data); +extern void dynarray_reset(void *pp, int *n); +extern char *tcc_strdup(const char *str); +extern char *pstrcpy(char *buf, size_t buf_size, const char *s); + +bool read_ldsoconf(xarray_t *dest, const char *directory) { DIR *dir; struct dirent *entry; - char path[1024]; - char *result = NULL; - size_t result_len = 0; - + char path[MAX_PATH]; dir = opendir(directory); if (dir == NULL) { - perror("opendir"); - return NULL; + _err("%s: error reading directory: %s",__func__,directory); + return false; } - while ((entry = readdir(dir)) != NULL) { - struct stat st; - snprintf(path, sizeof(path), "%s/%s", directory, entry->d_name); - + struct stat st; + cwk_path_join(directory,entry->d_name,path,MAX_PATH); // Check if it's a regular file if (stat(path, &st) == 0 && S_ISREG(st.st_mode)) { FILE *file = fopen(path, "r"); - if (file == NULL) { - perror("fopen"); + if (!file) { + _err("%s: error opening file: %s",__func__,path); continue; } - - char line[256]; + char line[512]; while (fgets(line, sizeof(line), file) != NULL) { - // Remove newline character at the end of the line - line[strcspn(line, "\n")] = 0; // Skip lines that are comments - if (line[0] == '#') continue; - - // Append the line to the result string - size_t line_len = strlen(line); - result = realloc(result, result_len + line_len + 2); // +2 for colon and null terminator - if (result == NULL) { - perror("realloc"); - fclose(file); - closedir(dir); - return NULL; - } - if (result_len == 0) { - strcpy(result, line); - } else { - strcat(result, ":"); - strcat(result, line); - } - result_len += line_len + 1; + if (line[0] != '/') continue; + size_t len = strlen(line); + if(line[len-1]=='\n') line[len-1]=0x0; + // add the line to the result array + XArray_AddData(dest,line,len); } fclose(file); } } - closedir(dir); - return result; + return true; } -// int main() { -// char *result = read_ld_so_conf_d("/etc/ld.so.conf.d"); -// if (result != NULL) { -// printf("Colon-separated string: %s\n", result); -// free(result); -// } -// return 0; -// } - void detect_file_type(const char *filename) { struct stat st; if (lstat(filename, &st) == -1) { @@ -310,7 +282,7 @@ static int ld_add_file(LDState *s1, const char filename[]) { } static int tcc_error_noabort(char *msg) { - _err("ldscript: %s",msg); + _err("Error in ldscript parser: %s",msg); return 1; } diff --git a/src/linker.h b/src/elflinker.h similarity index 100% rename from src/linker.h rename to src/elflinker.h From ceab4be05dc29be9d24aa04fa0c927936abd220d Mon Sep 17 00:00:00 2001 From: Jaromil Date: Fri, 3 Jan 2025 10:05:34 +0100 Subject: [PATCH 4/5] fix: improve ldsoconf parser and use absolute paths the new_abspath function will convert any relative path into absolute --- src/cjit.c | 51 +++++++++++++++++++++++++++++------------------ src/cjit.h | 4 ++++ src/elflinker.c | 53 +++++++++++++++++++++++++++++-------------------- src/elflinker.h | 8 ++++++-- src/file.c | 43 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 117 insertions(+), 42 deletions(-) diff --git a/src/cjit.c b/src/cjit.c index 0f15b1a..8ca5963 100644 --- a/src/cjit.c +++ b/src/cjit.c @@ -21,7 +21,7 @@ #include #include #include - +#include #include #include #include // _err/_out @@ -50,6 +50,9 @@ extern void win_compat_usleep(unsigned int microseconds); extern ssize_t win_compat_getline(char **lineptr, size_t *n, FILE *stream); extern bool get_winsdkpath(char *dst, size_t destlen); +// from file.c +extern char *new_abspath(const char *path); + static bool cjit_mkdtemp(CJITState *cjit) { char tempDir[MAX_PATH]; #if defined(WINDOWS) @@ -182,8 +185,8 @@ static bool cjit_setup(CJITState *cjit) { } } tcc_add_sysinclude_path(tcc(cjit), cjit->tmpdir); - tcc_add_sysinclude_path(tcc(cjit), "."); - tcc_add_sysinclude_path(tcc(cjit), "include"); // TODO: check if exists +// tcc_add_sysinclude_path(tcc(cjit), "."); +// tcc_add_sysinclude_path(tcc(cjit), "include"); // TODO: check if exists #if defined(WINDOWS) { @@ -213,16 +216,9 @@ static bool cjit_setup(CJITState *cjit) { } #endif -#if defined(LINUX) - { - xarray_t ldsoconf; - XArray_Init(&ldsoconf,3,0); - read_ldsoconf(&ldsoconf,"/etc/ld.so.conf.d"); - int len = XArray_Used(&ldsoconf); - for(int i=0;ilibpaths,"/etc/ld.so.conf"); + read_ldsoconf_dir(cjit->libpaths,"/etc/ld.so.conf.d"); #endif cjit->done_setup = true; @@ -261,6 +257,9 @@ bool cjit_status(CJITState *cjit) { #if !(defined TCC_TARGET_PE || defined TCC_TARGET_MACHO) _err("ELF interpreter: %s",CONFIG_TCC_ELFINTERP); #endif + + //////////////////////// + // call cjit_setup here setup; { int i; @@ -274,8 +273,10 @@ bool cjit_status(CJITState *cjit) { used = XArray_Used(cjit->libpaths); if(used) { _err("Library paths (%u)",used); - for(i=0;ilibpaths,i)); + for(i=0;ilibpaths,i); + _err("+ %s",d?d:"(null)"); + } } used = XArray_Used(cjit->libs); if(used) { @@ -592,14 +593,26 @@ void cjit_define_symbol(CJITState *cjit, const char *sym, const char *value) { if(cjit->verbose)_err("+D %s %s",sym,value?value:""); } void cjit_add_include_path(CJITState *cjit, const char *path) { - tcc_add_include_path(tcc(cjit), path); + const char *restrict toadd = new_abspath(path); + if(!toadd) { + _err("%s: absolute path error: %s",__func__,path); + return; + } + tcc_add_include_path(tcc(cjit), toadd); + free(toadd); debug("+I %s",path); } // TODO: temporary, to be reimplemented in linker.c void cjit_add_library_path(CJITState *cjit, const char *path) { - tcc_add_library_path(tcc(cjit), path); - add(libpaths,path); - debug("+L %s",path); + const char *restrict toadd = new_abspath(path); + if(!toadd) { + _err("%s: absolute path error: %s",__func__,path); + return; + } + tcc_add_library_path(tcc(cjit), toadd); + add(libpaths,toadd); + free(toadd); + debug("+L %s",toadd); } // TODO: temporary, to be reimplemented in linker.c void cjit_add_library(CJITState *cjit, const char *path) { diff --git a/src/cjit.h b/src/cjit.h index 04299ed..9e12b40 100644 --- a/src/cjit.h +++ b/src/cjit.h @@ -23,6 +23,10 @@ #include #include +#if !defined(MAX_PATH) +#define MAX_PATH 512 +#endif + // passed to cjit_exec with CJIT execution parameters struct CJITState { void *TCC; // the tinyCC context diff --git a/src/elflinker.c b/src/elflinker.c index d1f478d..3d279d2 100644 --- a/src/elflinker.c +++ b/src/elflinker.c @@ -22,12 +22,11 @@ // interpret a subset of GNU ldscripts to handle dummy .so files #include -#if defined(LINUX) +#if defined(POSIX) #define MAX_PATH 512 #include -#include -#include #include +#include #define CH_EOF (-1) //end of file #define LD_TOK_NAME 256 @@ -38,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -49,7 +49,29 @@ extern void dynarray_reset(void *pp, int *n); extern char *tcc_strdup(const char *str); extern char *pstrcpy(char *buf, size_t buf_size, const char *s); -bool read_ldsoconf(xarray_t *dest, const char *directory) { +bool read_ldsoconf(xarray_t *dest, char *path) { + FILE *file = fopen(path, "r"); + if (!file) { + _err("%s: error opening file: %s",__func__,path); + _err("%s: %s",strerror(errno)); + return false; + } + // TODO: optimize by allocating the buffer inside a xarray data + // struct to avoid double memcpy + char line[MAX_PATH]; + while (fgets(line, MAX_PATH, file) != NULL) { + // Skip lines that aren't paths + if (line[0] != '/') continue; + size_t len = strlen(line); + if(line[len-1]=='\n') line[len-1]=0x0; + // add the line to the result array + XArray_AddData(dest,line,len+1); + } + fclose(file); + return true; +} + +bool read_ldsoconf_dir(xarray_t *dest, const char *directory) { DIR *dir; struct dirent *entry; char path[MAX_PATH]; @@ -63,23 +85,12 @@ bool read_ldsoconf(xarray_t *dest, const char *directory) { cwk_path_join(directory,entry->d_name,path,MAX_PATH); // Check if it's a regular file if (stat(path, &st) == 0 && S_ISREG(st.st_mode)) { - FILE *file = fopen(path, "r"); - if (!file) { - _err("%s: error opening file: %s",__func__,path); - continue; - } - char line[512]; - while (fgets(line, sizeof(line), file) != NULL) { - // Skip lines that are comments - if (line[0] != '/') continue; - size_t len = strlen(line); - if(line[len-1]=='\n') line[len-1]=0x0; - // add the line to the result array - XArray_AddData(dest,line,len); - } - fclose(file); - } - } + if(! read_ldsoconf(dest,path) ) { + _err("%s: Xarray_AddData error: %s",__func__,directory); + continue; + } + } + } closedir(dir); return true; } diff --git a/src/elflinker.h b/src/elflinker.h index e49595b..104c186 100644 --- a/src/elflinker.h +++ b/src/elflinker.h @@ -1,5 +1,7 @@ -#ifndef __LDSCRIPT_H__ -#define __LDSCRIPT_H__ +#ifndef __ELFLINKER_H__ +#define __ELFLINKER_H__ + +#include struct LDState { int cc; @@ -9,6 +11,8 @@ struct LDState { }; typedef struct LDState LDState; +bool read_ldsoconf(xarray_t *dest, char *path); +bool read_ldsoconf_dir(xarray_t *dest, const char *directory); int cjit_load_ldscript(LDState *s1, char *path); #endif diff --git a/src/file.c b/src/file.c index a3959ce..a90e5dd 100644 --- a/src/file.c +++ b/src/file.c @@ -18,6 +18,7 @@ */ #include +#include #include #include @@ -103,6 +104,48 @@ char *load_stdin() { #endif } +char *new_abspath(const char *path) { + char tpath[MAX_PATH]; + char *res = NULL; + size_t len; + if(path[0]=='.' && path[1]==0x0) { + // argument is just . + if( getcwd(tpath,MAX_PATH) ) { + res = malloc(strlen(tpath)+1); + strcpy(res,tpath); + return(res); + } + } + if(path[0]=='.' && path[1]=='/') { + if( !getcwd(tpath,MAX_PATH) ) { + _err("%s: getcwd error: %s",__func__,strerror(errno)); + return(NULL); + } + res = malloc(strlen(tpath)+1); + strcpy(res,tpath); + len = cwk_path_get_absolute(res,path,tpath,MAX_PATH); + res = realloc(res, len+1); + strcpy(res,tpath); + return(res); + } + if(path[0]!='/') { + if( !getcwd(tpath,MAX_PATH) ) { + _err("%s: getcwd error: %s",__func__,strerror(errno)); + return(NULL); + } + res = malloc(strlen(tpath)+strlen(path)+16); + strcpy(res,tpath); + len = cwk_path_get_absolute(res,path,tpath,MAX_PATH); + res = realloc(res,len+1); + strcpy(res,tpath); + return(res); + } + len = cwk_path_normalize(path,tpath,MAX_PATH); + res = malloc(len+1); + strcpy(res,tpath); + return(res); +} + bool write_to_file(const char *path, const char *filename, const char *buf, unsigned int len) { FILE *fd; size_t written; From e2db907c96d163ce90feb166aa63af560091f580 Mon Sep 17 00:00:00 2001 From: Jaromil Date: Fri, 3 Jan 2025 10:06:28 +0100 Subject: [PATCH 5/5] fix: various cleanups and refining of POSIX platform definition build elf linker everywhere (selected by define) don't check ld.so.conf on apple/osx --- build/init.mk | 2 +- build/linux.mk | 1 - src/cjit.c | 6 +++--- src/cjit.h | 7 ------- src/file.c | 5 +++++ src/main.c | 12 +++++++----- src/platforms.h | 8 ++++++++ 7 files changed, 24 insertions(+), 17 deletions(-) diff --git a/build/init.mk b/build/init.mk index aeb1540..16c580f 100644 --- a/build/init.mk +++ b/build/init.mk @@ -15,7 +15,7 @@ CFLAGS ?= -O2 -fomit-frame-pointer ${cflags_stack_protect} cflags := ${CFLAGS} ${cflags_includes} -SOURCES := src/file.o src/cjit.o \ +SOURCES := src/file.o src/cjit.o src/elflinker.o \ src/main.o src/assets.o \ src/cwalk.o src/array.o \ src/muntar.o src/tinflate.o src/tinfgzip.o \ diff --git a/build/linux.mk b/build/linux.mk index b34a3f5..d97f843 100644 --- a/build/linux.mk +++ b/build/linux.mk @@ -5,7 +5,6 @@ cc := gcc cflags += -DLIBC_GNU -D_GNU_SOURCE cflags += -DKILO_SUPPORTED cflags += -DCJIT_BUILD_LINUX -SOURCES += src/elflinker.o all: embed-posix cjit diff --git a/src/cjit.c b/src/cjit.c index 8ca5963..50fd473 100644 --- a/src/cjit.c +++ b/src/cjit.c @@ -216,7 +216,7 @@ static bool cjit_setup(CJITState *cjit) { } #endif -#if defined(POSIX) +#if defined(UNIX) read_ldsoconf(cjit->libpaths,"/etc/ld.so.conf"); read_ldsoconf_dir(cjit->libpaths,"/etc/ld.so.conf.d"); #endif @@ -593,7 +593,7 @@ void cjit_define_symbol(CJITState *cjit, const char *sym, const char *value) { if(cjit->verbose)_err("+D %s %s",sym,value?value:""); } void cjit_add_include_path(CJITState *cjit, const char *path) { - const char *restrict toadd = new_abspath(path); + char *restrict toadd = new_abspath(path); if(!toadd) { _err("%s: absolute path error: %s",__func__,path); return; @@ -604,7 +604,7 @@ void cjit_add_include_path(CJITState *cjit, const char *path) { } // TODO: temporary, to be reimplemented in linker.c void cjit_add_library_path(CJITState *cjit, const char *path) { - const char *restrict toadd = new_abspath(path); + char *restrict toadd = new_abspath(path); if(!toadd) { _err("%s: absolute path error: %s",__func__,path); return; diff --git a/src/cjit.h b/src/cjit.h index 9e12b40..5e9fef7 100644 --- a/src/cjit.h +++ b/src/cjit.h @@ -91,10 +91,6 @@ extern bool extract_assets(CJITState *CJIT); ///////////// // from file.c extern char* file_load(const char *filename, unsigned int *len); -extern char *load_stdin(); -extern char* dir_load(const char *path); -extern bool write_to_file(const char *path, const char *filename, - const char *buf, unsigned int len); // terminal printing functions extern void _out(const char *fmt, ...); @@ -103,8 +99,5 @@ extern void _err(const char *fmt, ...); ///////////// // from repl.c extern int cjit_cli_tty(CJITState *cjit); -#ifdef KILO_SUPPORTED -extern int cjit_cli_kilo(CJITState *cjit); -#endif #endif diff --git a/src/file.c b/src/file.c index a90e5dd..61bfde9 100644 --- a/src/file.c +++ b/src/file.c @@ -171,6 +171,7 @@ bool write_to_file(const char *path, const char *filename, const char *buf, unsi return true; } +#if 0 // unused for now, dangerous to have if unnecessary static int rm_ftw(const char *pathname, const struct stat *sbuf, int type, struct FTW *ftwb) { @@ -205,7 +206,10 @@ bool rm_recursive(char *path) { } return true; } +#endif + +#if 0 #if !defined(WINDOWS) static char *full_content = NULL; @@ -273,3 +277,4 @@ char *dir_load(const char *path) #endif +#endif // 0 diff --git a/src/main.c b/src/main.c index 7fdc2d0..23d2e46 100644 --- a/src/main.c +++ b/src/main.c @@ -31,6 +31,8 @@ #include #include +extern char *load_stdin(); + #define MAX_ARG_STRING 1024 static int parse_value(char *str) { int i = 0; @@ -141,19 +143,19 @@ int main(int argc, char **argv) { strcpy(CJIT->output_filename,opt.arg); cjit_set_output(CJIT, EXE); } else if (c == 'L') { // library path - if(!CJIT->quiet)_err("lib path: %s",opt.arg); + if(CJIT->verbose)_err("arg lib path: %s",opt.arg); cjit_add_library_path(CJIT, opt.arg); } else if (c == 'l') { // library link - if(!CJIT->quiet)_err("lib: %s",opt.arg); + if(CJIT->verbose)_err("arg lib: %s",opt.arg); cjit_add_library(CJIT, opt.arg); } else if (c == 'C') { // cflags compiler options - if(!CJIT->quiet)_err("cflags: %s",opt.arg); + if(CJIT->verbose)_err("arg cflags: %s",opt.arg); cjit_set_tcc_options(CJIT->TCC, opt.arg); } else if (c == 'I') { // include paths in cflags - if(!CJIT->quiet)_err("inc: %s",opt.arg); + if(CJIT->verbose)_err("arg inc: %s",opt.arg); cjit_add_include_path(CJIT, opt.arg); } else if (c == 'e') { // entry point (default main) - if(!CJIT->quiet)_err("entry: %s",opt.arg); + if(!CJIT->quiet)_err("entry function: %s",opt.arg); if(CJIT->entry) free(CJIT->entry); CJIT->entry = malloc(strlen(opt.arg)+1); strcpy(CJIT->entry,opt.arg); diff --git a/src/platforms.h b/src/platforms.h index 7308d61..31bb0e9 100644 --- a/src/platforms.h +++ b/src/platforms.h @@ -19,18 +19,24 @@ #endif #if defined(__linux__) #define LINUX + #define POSIX + #define UNIX #define PLATFORM "GNU/Linux" #endif #if defined(__APPLE__) #define APPLE + #define POSIX #define PLATFORM "Apple/OSX" #endif #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) #define BSD + #define POSIX + #define UNIX #define PLATFORM "BSD" #endif #if defined(__ANDROID__) #define ANDROID + #define POSIX #define PLATFORM "Android" #endif #if defined(__EMSCRIPTEN__) @@ -39,10 +45,12 @@ #endif #if defined(__BEOS__) || defined(__HAIKU__) #define BEOS + #define POSIX #define PLATFORM "BEOS" #endif #if defined(__HAIKU__) #define HAIKU + #define POSIX #define PLATFORM "Haiku" #endif #endif