diff options
Diffstat (limited to 'src/bldprogs/genalias.cpp')
-rw-r--r-- | src/bldprogs/genalias.cpp | 500 |
1 files changed, 500 insertions, 0 deletions
diff --git a/src/bldprogs/genalias.cpp b/src/bldprogs/genalias.cpp new file mode 100644 index 00000000..073f169f --- /dev/null +++ b/src/bldprogs/genalias.cpp @@ -0,0 +1,500 @@ +/* $Id: genalias.cpp $ */ +/** @file + * genalias - generate a number of alias objects. + * + * @note The code has its origin with kLIBC and was added to VBox by the author. + */ + +/* + * Copyright (C) 2022-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <stdarg.h> +#include <stdio.h> +#include <iprt/stdint.h> +#include <string.h> +#include <time.h> +#include <assert.h> + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ +#if defined(RT_OS_DARWIN) || (defined(RT_ARCH_X86) && (defined(RT_OS_WINDOWS) || defined(RT_OS_OS2))) +# define GENALIAS_UNDERSCORED 1 +#else +# define GENALIAS_UNDERSCORED 0 +#endif + + + +static int Error(const char *pszFormat, ...) +{ + va_list va; + fprintf(stderr, "genalias: error: "); + va_start(va, pszFormat); + vfprintf(stderr, pszFormat, va); + va_end(va); + return 1; +} + +static int SyntaxError(const char *pszFormat, ...) +{ + va_list va; + fprintf(stderr, "genalias: syntax error: "); + va_start(va, pszFormat); + vfprintf(stderr, pszFormat, va); + va_end(va); + return 1; +} + +static int WriteAliasObjectAOUT(FILE *pOutput, const char *pszAlias, const char *pszReal) +{ +#pragma pack(1) + /* ASSUMES 32-bit target. */ + struct AoutHdr + { + uint32_t a_info; + uint32_t a_text; + uint32_t a_data; + uint32_t a_bss; + uint32_t a_syms; + uint32_t a_entry; + uint32_t a_trsize; + uint32_t a_drsize; + } Hdr; +#define OMAGIC 0407 + struct AoutSym + { + uint32_t n_strx; + uint8_t n_type; + int8_t n_other; + uint16_t n_desc; + uint32_t n_value; + } Sym; +#define N_EXT 1 +#define N_INDR 10 +#pragma pack() + const uint32_t cchAlias = (uint32_t)strlen(pszAlias); + const uint32_t cchReal = (uint32_t)strlen(pszReal); + uint32_t u32; + + /* write the header. */ + memset(&Hdr, 0, sizeof(Hdr)); + Hdr.a_info = OMAGIC; + Hdr.a_syms = 2 * sizeof(Sym); + if (fwrite(&Hdr, sizeof(Hdr), 1, pOutput) != 1) + return -2; + + /* The alias symbol. */ + Sym.n_strx = 4 + cchReal + 1 + GENALIAS_UNDERSCORED; + Sym.n_type = N_INDR | N_EXT; + Sym.n_other = 0; + Sym.n_desc = 0; + Sym.n_value = 0; + if (fwrite(&Sym, sizeof(Sym), 1, pOutput) != 1) + return -2; + + /* The real symbol. */ + Sym.n_strx = 4; + Sym.n_type = N_EXT; + Sym.n_other = 0; + Sym.n_desc = 0; + Sym.n_value = 0; + if (fwrite(&Sym, sizeof(Sym), 1, pOutput) != 1) + return -2; + + /* the string table. */ + u32 = 4 + cchReal + 1 + cchAlias + 1 + GENALIAS_UNDERSCORED * 2; + if (fwrite(&u32, 4, 1, pOutput) != 1) + return -2; +#if GENALIAS_UNDERSCORED + if (fputc('_', pOutput) == EOF) + return -2; +#endif + if (fwrite(pszReal, cchReal + 1, 1, pOutput) != 1) + return -2; +#if GENALIAS_UNDERSCORED + if (fputc('_', pOutput) == EOF) + return -2; +#endif + if (fwrite(pszAlias, cchAlias + 1, 1, pOutput) != 1) + return -2; + return 0; +} + +static int WriteAliasObjectCOFF(FILE *pOutput, const char *pszAlias, const char *pszReal, bool fUnderscored) +{ +#pragma pack(1) + struct CoffHdr + { + uint16_t Machine; + uint16_t NumberOfSections; + uint32_t TimeDateStamp; + uint32_t PointerToSymbolTable; + uint32_t NumberOfSymbols; + uint16_t SizeOfOptionalHeader; + uint16_t Characteristics; + } Hdr; + struct CoffShdr + { + char Name[8]; + uint32_t VirtualSize; + uint32_t VirtualAddress; + uint32_t SizeOfRawData; + uint32_t PointerToRawData; + uint32_t PointerToRelocations; + uint32_t PointerToLinenumbers; + uint16_t NumberOfRelocations; + uint16_t NumberOfLinenumbers; + uint32_t Characteristics; + } Shdr; +#define IMAGE_SCN_LNK_INFO 0x200 +#define IMAGE_SCN_LNK_REMOVE 0x800 + struct CoffSym + { + union + { + char ShortName[8]; + struct + { + uint32_t Zeros; + uint32_t Offset; + } s; + } u; + uint32_t Value; + uint16_t SectionNumber; + uint16_t Type; + uint8_t StorageClass; + uint8_t NumberOfAuxSymbols; + } Sym; +#define IMAGE_SYM_UNDEFINED 0 +#define IMAGE_SYM_TYPE_NULL 0 +#define IMAGE_SYM_CLASS_EXTERNAL 2 +#define IMAGE_SYM_CLASS_WEAK_EXTERNAL 105 + struct CoffAuxWeakExt + { + uint32_t TagIndex; + uint32_t Characteristics; + uint8_t padding[10]; + } Aux; +#define IMAGE_WEAK_EXTERN_SEARCH_ALIAS 3 + assert(sizeof(Hdr) == 20); assert(sizeof(Sym) == 18); assert(sizeof(Aux) == sizeof(Sym)); +#pragma pack() + const uint32_t cchAlias = (uint32_t)strlen(pszAlias); + const uint32_t cchReal = (uint32_t)strlen(pszReal); + uint32_t u32; + + /* write the header. */ + Hdr.Machine = 0 /*unknown*/; //0x14c /* i386 */; + Hdr.NumberOfSections = 1; + Hdr.TimeDateStamp = time(NULL); + Hdr.PointerToSymbolTable = sizeof(Hdr) + sizeof(Shdr); + Hdr.NumberOfSymbols = 3; + Hdr.SizeOfOptionalHeader = 0; + Hdr.Characteristics = 0; + if (fwrite(&Hdr, sizeof(Hdr), 1, pOutput) != 1) + return -2; + + /* The directive section. */ + if (Hdr.NumberOfSections == 1) + { + memset(&Shdr, 0, sizeof(Shdr)); + memcpy(Shdr.Name, ".drectve", 8); + Shdr.Characteristics = IMAGE_SCN_LNK_REMOVE | IMAGE_SCN_LNK_INFO; + if (fwrite(&Shdr, sizeof(Shdr), 1, pOutput) != 1) + return -2; + } + + /* The real symbol. */ + memset(&Sym, 0, sizeof(Sym)); + Sym.u.s.Offset = 4; + Sym.SectionNumber = IMAGE_SYM_UNDEFINED; + Sym.Type = IMAGE_SYM_TYPE_NULL; + Sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL; + if (fwrite(&Sym, sizeof(Sym), 1, pOutput) != 1) + return -2; + + /* The alias symbol. */ + memset(&Sym, 0, sizeof(Sym)); + Sym.u.s.Offset = fUnderscored + cchReal + 1 + 4; + Sym.SectionNumber = IMAGE_SYM_UNDEFINED; + Sym.Type = IMAGE_SYM_TYPE_NULL; + Sym.StorageClass = IMAGE_SYM_CLASS_WEAK_EXTERNAL; + Sym.NumberOfAuxSymbols = 1; + if (fwrite(&Sym, sizeof(Sym), 1, pOutput) != 1) + return -2; + + /* aux entry for that. */ + memset(&Aux, 0, sizeof(Aux)); + Aux.TagIndex = 0; + Aux.Characteristics = IMAGE_WEAK_EXTERN_SEARCH_ALIAS; + if (fwrite(&Aux, sizeof(Aux), 1, pOutput) != 1) + return -2; + + /* the string table. */ + u32 = 4 + cchReal + 1 + cchAlias + 1 + fUnderscored * 2; + if (fwrite(&u32, 4, 1, pOutput) != 1) + return -2; + if (fUnderscored) + if (fputc('_', pOutput) == EOF) + return -2; + if (fwrite(pszReal, cchReal + 1, 1, pOutput) != 1) + return -2; + if (fUnderscored) + if (fputc('_', pOutput) == EOF) + return -2; + if (fwrite(pszAlias, cchAlias + 1, 1, pOutput) != 1) + return -2; + return 0; +} + +static int WriteAliasObjectTargetCOFF(FILE *pOutput, const char *pszAlias, const char *pszReal) +{ + return WriteAliasObjectCOFF(pOutput, pszAlias, pszReal, GENALIAS_UNDERSCORED); +} + +static int WriteAliasObjectX86COFF(FILE *pOutput, const char *pszAlias, const char *pszReal) +{ + return WriteAliasObjectCOFF(pOutput, pszAlias, pszReal, true /*fUnderscored*/); +} + +static int WriteAliasObjectAmd64COFF(FILE *pOutput, const char *pszAlias, const char *pszReal) +{ + return WriteAliasObjectCOFF(pOutput, pszAlias, pszReal, false /*fUnderscored*/); +} + + +static int WriteAliasObjectELF(FILE *pOutput, const char *pszAlias, const char *pszReal) +{ + RT_NOREF(pOutput, pszAlias, pszReal); + fprintf(stderr, "ELF does not support proper aliasing, only option seems to be adding weak symbols with the strong one.\n"); + return -1; +} + +static int WriteAliasObjectOMF(FILE *pOutput, const char *pszAlias, const char *pszReal) +{ + const uint32_t cchAlias = (uint32_t)strlen(pszAlias); + const uint32_t cchReal = (uint32_t)strlen(pszReal); + //const uint32_t cchName = cchAlias > 250 ? 250 : cchAlias; + uint32_t cch; + + if (cchReal >= 250) + return Error("Symbol '%s' is too long!\n", pszReal); + if (cchAlias >= 250) + return Error("Symbol '%s' is too long!\n", pszAlias); + + /* THEADR */ + fputc(0x80, pOutput); + cch = cchAlias + 2; + fputc(cch & 0xff, pOutput); + fputc(cch >> 8, pOutput); + fputc(cchAlias, pOutput); + fwrite(pszAlias, cchAlias, 1, pOutput); + fputc(0, pOutput); /* CRC */ + + /* ALIAS */ + fputc(0xc6, pOutput); + cch = cchAlias + 1 + cchReal + 1 + GENALIAS_UNDERSCORED * 2 + 1; + fputc(cch & 0xff, pOutput); + fputc(cch >> 8, pOutput); + fputc(cchAlias + GENALIAS_UNDERSCORED, pOutput); + if (GENALIAS_UNDERSCORED) + fputc('_', pOutput); + fwrite(pszAlias, cchAlias, 1, pOutput); + fputc(cchReal + GENALIAS_UNDERSCORED, pOutput); + if (GENALIAS_UNDERSCORED) + fputc('_', pOutput); + fwrite(pszReal, cchReal, 1, pOutput); + fputc(0, pOutput); /* CRC */ + + /* MODEND32 */ + fputc(0x8b, pOutput); + fputc(2, pOutput); + fputc(0, pOutput); + fputc(0, pOutput); + if (fputc(0, pOutput) == EOF) /* CRC */ + return -2; + return 0; +} + +static int WriteAliasObjectMACHO(FILE *pOutput, const char *pszAlias, const char *pszReal) +{ + RT_NOREF(pOutput, pszAlias, pszReal); + fprintf(stderr, "Mach-O support not implemented yet\n"); + return -1; +} + +static int CreateAlias(char *pszBuf, size_t cchInput, char *pszFileBuf, char *pszFilename, + int (*pfnWriter)(FILE *, const char *, const char *)) +{ + char *pszAlias = pszBuf; + char *pszReal; + char *pszFile; + FILE *pOutput; + int rc; + RT_NOREF(cchInput); + + /* + * Parse input. + */ + pszReal = strchr(pszBuf, '='); + if (!pszReal) + return Error("Malformed request: '%s'\n", pszBuf); + *pszReal++ = '\0'; + + pszFile = strchr(pszReal, '='); + if (pszFile) + { + *pszFile++ = '\0'; + strcpy(pszFilename, pszFile); + } + else + strcat(strcpy(pszFilename, pszAlias), ".o"); + + /* + * Open the output file. + */ + pOutput = fopen(pszFileBuf, "wb"); + if (!pOutput) + return Error("Failed to open '%s' for writing!\n", pszFileBuf); + rc = pfnWriter(pOutput, pszAlias, pszReal); + if (rc == -2) + rc = Error("Write error writing '%s'!\n", pszFileBuf); + fclose(pOutput); + return rc; +} + + +static int Syntax(void) +{ + printf("syntax: genalias -f <format> -D <output-dir> alias=real[=file] [alias2=real2[=file2] [..]]\n" + " OR\n" + " genalias -f <format> -D <output-dir> -r <response-file>\n" + "\n" + "Format can be: aout, coff or omf\n" + "The responsefile is a single argument per line.\n"); + return 1; +} + + +int main(int argc, char **argv) +{ + static char s_szBuf[4096]; + static char s_szFile[1024 + sizeof(s_szBuf)]; + int (*pfnWriter)(FILE *pOutput, const char *pszAlias, const char *pszReal); + char *pszFilename; + int i; + int rc; + + /* + * Parse arguments. + */ + if (argc <= 5) + return Syntax(); + if (strcmp(argv[1], "-f")) + return SyntaxError("Expected -f as the 1st argument.\n"); + if (!strcmp(argv[2], "aout")) + pfnWriter = WriteAliasObjectAOUT; + else if (!strcmp(argv[2], "coff")) + pfnWriter = WriteAliasObjectTargetCOFF; + else if (!strcmp(argv[2], "coff.x86")) + pfnWriter = WriteAliasObjectX86COFF; + else if (!strcmp(argv[2], "coff.amd64")) + pfnWriter = WriteAliasObjectAmd64COFF; + else if (!strcmp(argv[2], "elf")) + pfnWriter = WriteAliasObjectELF; + else if (!strcmp(argv[2], "omf")) + pfnWriter = WriteAliasObjectOMF; + else if (!strcmp(argv[2], "macho")) + pfnWriter = WriteAliasObjectMACHO; + else + return SyntaxError("Unknown format '%s'.\n", argv[2]); + if (strcmp(argv[3], "-D")) + return SyntaxError("Expected -D as the 3rd argument\n"); + if (!*argv[4]) + return SyntaxError("The output directory name is empty.\n"); + size_t cchFile = strlen(argv[4]); + if (cchFile > sizeof(s_szFile) - sizeof(s_szBuf)) + return SyntaxError("The output directory name is too long.\n"); + memcpy(s_szFile, argv[4], cchFile); + s_szFile[cchFile++] = '/'; + pszFilename = &s_szFile[cchFile]; + + /* anything to do? */ + if (argc == 5) + return 0; + + rc = 0; + if (!strcmp(argv[5], "-r")) + { + /* + * Responsefile. + */ + FILE *pResp; + if (argc <= 6) + return SyntaxError("Missing response file name\n"); + pResp = fopen(argv[6], "rt"); + if (!pResp) + return Error("Failed to open '%s' for reading.\n", argv[6]); + + i = 0; + while (fgets(s_szBuf, sizeof(s_szBuf), pResp)) + { + size_t cch = strlen(s_szBuf); + i++; + if (cch == sizeof(s_szBuf) && s_szBuf[cch - 1] != '\n') + { + rc = Error("Line %d is too long!\n", i); + break; + } + if (cch && s_szBuf[cch - 1] == '\n') + s_szBuf[--cch] = '\0'; + rc = CreateAlias(s_szBuf, cch, s_szFile, pszFilename, pfnWriter); + if (rc) + break; + } + + fclose(pResp); + } + else + { + /* + * Alias descriptors. + */ + for (i = 5; i < argc; i++) + { + size_t cch = strlen(argv[i]); + if (cch >= sizeof(s_szBuf)) + return SyntaxError("Argument %d is too long\n", i); + memcpy(s_szBuf, argv[i], cch + 1); + rc = CreateAlias(s_szBuf, cch, s_szFile, pszFilename, pfnWriter); + if (rc) + break; + } + } + return rc; +} + |