/* * Copyright (c) 2008-2023 Jonathan Schleifer <js@nil.im> * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in * the packaging of this file. * * Alternatively, it may be distributed under the terms of the GNU General * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #include "config.h" #import "OFDNSResourceRecord.h" #import "OFHTTPRequest.h" #import "OFSocket.h" #import "OFStdIOStream.h" #import "OFString.h" #import "macros.h" #import "amiga-glue.h" #import "amiga-library.h" #include <exec/libraries.h> #include <exec/nodes.h> #include <exec/resident.h> #include <proto/exec.h> #define CONCAT_VERSION2(major, minor) #major "." #minor #define CONCAT_VERSION(major, minor) CONCAT_VERSION2(major, minor) #define VERSION_STRING CONCAT_VERSION(OBJFW_LIB_MAJOR, OBJFW_LIB_MINOR) #if defined(OF_AMIGAOS_M68K) # define DATA_OFFSET 0x7FFE #elif defined(OF_MORPHOS) # define DATA_OFFSET 0x8000 #endif #ifdef OF_AMIGAOS_M68K # define OF_M68K_REG(reg) __asm__(#reg) #else # define OF_M68K_REG(reg) #endif /* This always needs to be the first thing in the file. */ int _start(void) { return -1; } #ifdef OF_AMIGAOS_M68K void __init_eh(void) { /* Taken care of by OFInit() */ } #endif struct ObjFWBase { struct Library library; void *segList; struct ObjFWBase *parent; char *dataSeg; bool initialized; }; #ifdef OF_AMIGAOS_M68K extern uintptr_t __CTOR_LIST__[]; extern const void *_EH_FRAME_BEGINS__; extern void *_EH_FRAME_OBJECTS__; #endif #ifdef OF_MORPHOS const ULONG __abox__ = 1; #endif struct ExecBase *SysBase; struct OFLibC libC; struct Library *ObjFWRTBase; #if defined(OF_AMIGAOS_M68K) __asm__ ( ".text\n" ".globl ___restore_a4\n" ".align 1\n" "___restore_a4:\n" " movea.l 42(a6), a4\n" " rts" ); #elif defined(OF_MORPHOS) /* All __saveds functions in this file need to use the M68K ABI */ __asm__ ( ".section .text\n" ".align 2\n" "__restore_r13:\n" " lwz %r13, 56(%r2)\n" " lwz %r13, 44(%r13)\n" " blr\n" ); #endif static OF_INLINE char * getDataSeg(void) { char *dataSeg; #if defined(OF_AMIGAOS_M68K) __asm__ ( "move.l #___a4_init, %0" : "=r"(dataSeg) ); #elif defined(OF_MORPHOS) __asm__ ( "lis %0, __r13_init@ha\n\t" "la %0, __r13_init@l(%0)" : "=r"(dataSeg) ); #endif return dataSeg; } static OF_INLINE size_t getDataSize(void) { size_t dataSize; #if defined(OF_AMIGAOS_M68K) __asm__ ( "move.l #___data_size, %0\n\t" "add.l #___bss_size, %0" : "=r"(dataSize) ); #elif defined(OF_MORPHOS) __asm__ ( "lis %0, __sdata_size@ha\n\t" "la %0, __sdata_size@l(%0)\n\t" "lis %%r9, __sbss_size@ha\n\t" "la %%r9, __sbss_size@l(%%r9)\n\t" "add %0, %0, %%r9" : "=r"(dataSize) :: "r9" ); #endif return dataSize; } static OF_INLINE size_t * getDataDataRelocs(void) { size_t *dataDataRelocs; #if defined(OF_AMIGAOS_M68K) __asm__ ( "move.l #___datadata_relocs, %0" : "=r"(dataDataRelocs) ); #elif defined(OF_MORPHOS) __asm__ ( "lis %0, __datadata_relocs@ha\n\t" "la %0, __datadata_relocs@l(%0)\n\t" : "=r"(dataDataRelocs) ); #endif return dataDataRelocs; } static struct Library * libInit(struct ObjFWBase *base OF_M68K_REG(d0), void *segList OF_M68K_REG(a0), struct ExecBase *sysBase OF_M68K_REG(a6)) { #if defined(OF_AMIGAOS_M68K) __asm__ __volatile__ ( "move.l a6, _SysBase" :: "a"(sysBase) ); #elif defined(OF_MORPHOS) __asm__ __volatile__ ( "lis %%r9, SysBase@ha\n\t" "stw %0, SysBase@l(%%r9)" :: "r"(sysBase) : "r9" ); #endif base->segList = segList; base->parent = NULL; base->dataSeg = getDataSeg(); return &base->library; } struct Library *__saveds libOpen(void) { OF_M68K_ARG(struct ObjFWBase *, base, a6) struct ObjFWBase *child; size_t dataSize, *dataDataRelocs; ptrdiff_t displacement; if (base->parent != NULL) return NULL; base->library.lib_OpenCnt++; base->library.lib_Flags &= ~LIBF_DELEXP; /* * We cannot use malloc here, as that depends on the libC passed from * the application. */ if ((child = AllocMem(base->library.lib_NegSize + base->library.lib_PosSize, MEMF_ANY)) == NULL) { base->library.lib_OpenCnt--; return NULL; } memcpy(child, (char *)base - base->library.lib_NegSize, base->library.lib_NegSize + base->library.lib_PosSize); child = (struct ObjFWBase *)((char *)child + base->library.lib_NegSize); child->library.lib_OpenCnt = 1; child->parent = base; dataSize = getDataSize(); if ((child->dataSeg = AllocMem(dataSize, MEMF_ANY)) == NULL) { FreeMem((char *)child - child->library.lib_NegSize, child->library.lib_NegSize + child->library.lib_PosSize); base->library.lib_OpenCnt--; return NULL; } memcpy(child->dataSeg, base->dataSeg - DATA_OFFSET, dataSize); dataDataRelocs = getDataDataRelocs(); displacement = child->dataSeg - (base->dataSeg - DATA_OFFSET); for (size_t i = 1; i <= dataDataRelocs[0]; i++) *(long *)(child->dataSeg + dataDataRelocs[i]) += displacement; child->dataSeg += DATA_OFFSET; return &child->library; } static void * expunge(struct ObjFWBase *base, struct ExecBase *sysBase) { #define SysBase sysBase void *segList; if (base->parent != NULL) { base->parent->library.lib_Flags |= LIBF_DELEXP; return 0; } if (base->library.lib_OpenCnt > 0) { base->library.lib_Flags |= LIBF_DELEXP; return 0; } segList = base->segList; Remove(&base->library.lib_Node); FreeMem((char *)base - base->library.lib_NegSize, base->library.lib_NegSize + base->library.lib_PosSize); return segList; #undef SysBase } static void *__saveds libExpunge(void) { OF_M68K_ARG(struct ObjFWBase *, base, a6) return expunge(base, SysBase); } static void *__saveds libClose(void) { /* * SysBase becomes invalid during this function, so we store it in * sysBase and add a define to make the inlines use the right one. */ struct ExecBase *sysBase = SysBase; #define SysBase sysBase OF_M68K_ARG(struct ObjFWBase *, base, a6) if (base->parent != NULL) { struct ObjFWBase *parent; #ifdef OF_AMIGAOS_M68K if (base->initialized) for (void *const *frame = _EH_FRAME_BEGINS__; *frame != NULL;) libC.__deregister_frame_info(*frame++); #endif parent = base->parent; FreeMem(base->dataSeg - DATA_OFFSET, getDataSize()); FreeMem((char *)base - base->library.lib_NegSize, base->library.lib_NegSize + base->library.lib_PosSize); base = parent; } if (--base->library.lib_OpenCnt == 0 && (base->library.lib_Flags & LIBF_DELEXP)) return expunge(base, sysBase); return NULL; #undef SysBase } static void * libNull(void) { return NULL; } static void __saveds OFInitPart2(uintptr_t *iter0, struct Library *RTBase) { uintptr_t *iter; ObjFWRTBase = RTBase; for (iter = iter0; *iter != 0; iter++); while (iter > iter0) { void (*ctor)(void) = (void (*)(void))*--iter; ctor(); } } bool OFInit(unsigned int version, struct OFLibC *libC_, struct Library *RTBase) { #ifdef OF_AMIGAOS_M68K OF_M68K_ARG(struct ObjFWBase *, base, a6) #else register struct ObjFWBase *r12 __asm__("r12"); struct ObjFWBase *base = r12; #endif #ifdef OF_MORPHOS void *frame; #endif uintptr_t *iter0; if (version > 1) return false; if (base->initialized) return true; memcpy(&libC, libC_, sizeof(libC)); #ifdef OF_AMIGAOS_M68K for (void *const *frame = _EH_FRAME_BEGINS__, **object = _EH_FRAME_OBJECTS__; *frame != NULL;) libC.__register_frame_info(*frame++, *object++); iter0 = &__CTOR_LIST__[1]; #elif defined(OF_MORPHOS) __asm__ ( "lis %0, __EH_FRAME_BEGIN__@ha\n\t" "la %0, __EH_FRAME_BEGIN__@l(%0)\n\t" "lis %1, __CTOR_LIST__@ha\n\t" "la %1, __CTOR_LIST__@l(%1)\n\t" : "=r"(frame), "=r"(iter0) ); libC.__register_frame(frame); #endif OFInitPart2(iter0, RTBase); base->initialized = true; return true; } void * malloc(size_t size) { return libC.malloc(size); } void * calloc(size_t count, size_t size) { return libC.calloc(count, size); } void * realloc(void *ptr, size_t size) { return libC.realloc(ptr, size); } void free(void *ptr) { libC.free(ptr); } void abort(void) { libC.abort(); OF_UNREACHABLE } #ifdef HAVE_SJLJ_EXCEPTIONS int _Unwind_SjLj_RaiseException(void *ex) { return libC._Unwind_SjLj_RaiseException(ex); } #else int _Unwind_RaiseException(void *ex) { return libC._Unwind_RaiseException(ex); } #endif void _Unwind_DeleteException(void *ex) { libC._Unwind_DeleteException(ex); } void * _Unwind_GetLanguageSpecificData(void *ctx) { return libC._Unwind_GetLanguageSpecificData(ctx); } uintptr_t _Unwind_GetRegionStart(void *ctx) { return libC._Unwind_GetRegionStart(ctx); } uintptr_t _Unwind_GetDataRelBase(void *ctx) { return libC._Unwind_GetDataRelBase(ctx); } uintptr_t _Unwind_GetTextRelBase(void *ctx) { return libC._Unwind_GetTextRelBase(ctx); } uintptr_t _Unwind_GetIP(void *ctx) { return libC._Unwind_GetIP(ctx); } uintptr_t _Unwind_GetGR(void *ctx, int gr) { return libC._Unwind_GetGR(ctx, gr); } void _Unwind_SetIP(void *ctx, uintptr_t ip) { libC._Unwind_SetIP(ctx, ip); } void _Unwind_SetGR(void *ctx, int gr, uintptr_t value) { libC._Unwind_SetGR(ctx, gr, value); } #ifdef HAVE_SJLJ_EXCEPTIONS void _Unwind_SjLj_Resume(void *ex) { libC._Unwind_SjLj_Resume(ex); } #else void _Unwind_Resume(void *ex) { libC._Unwind_Resume(ex); } #endif #ifdef OF_AMIGAOS_M68K void __register_frame_info(const void *begin, void *object) { libC.__register_frame_info(begin, object); } void *__deregister_frame_info(const void *begin) { return libC.__deregister_frame_info(begin); } #endif #ifdef OF_MORPHOS void __register_frame(void *frame) { libC.__register_frame(frame); } void __deregister_frame(void *frame) { libC.__deregister_frame(frame); } #endif int * OFErrNo(void) { return libC.errNo(); } #ifdef OF_MORPHOS int vasprintf(char **restrict strp, const char *restrict fmt, va_list args) { return libC.vasprintf(strp, fmt, args); } int asprintf(char **restrict strp, const char *restrict fmt, ...) { va_list args; int ret; va_start(args, fmt); ret = vasprintf(strp, fmt, args); va_end(args); return ret; } #else int vsnprintf(char *restrict str, size_t size, const char *restrict fmt, va_list args) { return libC.vsnprintf(str, size, fmt, args); } #endif float strtof(const char *str, char **endptr) { return libC.strtof(str, endptr); } double strtod(const char *str, char **endptr) { return libC.strtod(str, endptr); } #ifdef OF_MORPHOS struct tm * gmtime_r(const time_t *time, struct tm *tm) { return libC.gmtime_r(time, tm); } struct tm * localtime_r(const time_t *time, struct tm *tm) { return libC.localtime_r(time, tm); } #endif int gettimeofday(struct timeval *tv, struct timezone *tz) { return libC.gettimeofday(tv, tz); } time_t mktime(struct tm *tm) { return libC.mktime(tm); } size_t strftime(char *str, size_t len, const char *fmt, const struct tm *tm) { return libC.strftime(str, len, fmt, tm); } void exit(int status) { libC.exit(status); OF_UNREACHABLE } int atexit(void (*function)(void)) { return libC.atexit(function); } OFSignalHandler signal(int sig, OFSignalHandler func) { return libC.signal(sig, func); } char * setlocale(int category, const char *locale) { return libC.setlocale(category, locale); } int _Unwind_Backtrace(int (*callback)(void *, void *), void *data) { return libC._Unwind_Backtrace(callback, data); } #ifdef OF_MORPHOS int setjmp(jmp_buf env) { return libC.setjmp(env); } void longjmp(jmp_buf env, int val) { libC.longjmp(env, val); } #endif void OFPBKDF2Wrapper(const OFPBKDF2Parameters *parameters) { OFPBKDF2(*parameters); } void OFScryptWrapper(const OFScryptParameters *parameters) { OFScrypt(*parameters); } #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpedantic" static CONST_APTR functionTable[] = { #ifdef OF_MORPHOS (CONST_APTR)FUNCARRAY_BEGIN, (CONST_APTR)FUNCARRAY_32BIT_NATIVE, #endif (CONST_APTR)libOpen, (CONST_APTR)libClose, (CONST_APTR)libExpunge, (CONST_APTR)libNull, #ifdef OF_MORPHOS (CONST_APTR)-1, (CONST_APTR)FUNCARRAY_32BIT_SYSTEMV, #endif #include "amiga-funcarray.inc" (CONST_APTR)-1, #ifdef OF_MORPHOS (CONST_APTR)FUNCARRAY_END #endif }; #pragma GCC diagnostic pop static struct { ULONG dataSize; CONST_APTR *functionTable; ULONG *dataTable; struct Library *(*initFunc)( struct ObjFWBase *base OF_M68K_REG(d0), void *segList OF_M68K_REG(a0), struct ExecBase *execBase OF_M68K_REG(a6)); } init_table = { sizeof(struct ObjFWBase), functionTable, NULL, libInit }; struct Resident resident = { .rt_MatchWord = RTC_MATCHWORD, .rt_MatchTag = &resident, .rt_EndSkip = &resident + 1, .rt_Flags = RTF_AUTOINIT #ifdef OF_MORPHOS | RTF_PPC | RTF_EXTENDED #endif , .rt_Version = OBJFW_LIB_MAJOR, .rt_Type = NT_LIBRARY, .rt_Pri = 0, .rt_Name = (char *)OBJFW_AMIGA_LIB, .rt_IdString = (char *)"ObjFW " VERSION_STRING " \xA9 2008-2023 Jonathan Schleifer", .rt_Init = &init_table, #ifdef OF_MORPHOS .rt_Revision = OBJFW_LIB_MINOR, .rt_Tags = NULL, #endif }; #if defined(OF_MORPHOS) __asm__ ( ".section .eh_frame, \"aw\"\n" ".globl __EH_FRAME_BEGIN__\n" ".type __EH_FRAME_BEGIN__, @object\n" "__EH_FRAME_BEGIN__:\n" ".section .ctors, \"aw\"\n" ".globl __CTOR_LIST__\n" ".type __CTOR_LIST__, @object\n" "__CTOR_LIST__:\n" ".section .text" ); #elif defined(OF_AMIGAOS_M68K) __asm__ ( ".section .list___EH_FRAME_BEGINS__, \"aw\"\n" ".globl __EH_FRAME_BEGIN__\n" ".type __EH_FRAME_BEGIN__, @object\n" "__EH_FRAME_BEGINS__:\n" ".section .dlist___EH_FRAME_OBJECTS__, \"aw\"\n" ".globl __EH_FRAME_OBJECTS__\n" ".type __EH_FRAME_OBJECTS__, @object\n" "__EH_FRAME_OBJECTS__:\n" ".section .list___CTOR_LIST__, \"aw\"\n" ".globl ___CTOR_LIST__\n" ".type ___CTOR_LIST__, @object\n" "___CTOR_LIST__:\n" ".section .text" ); #endif