Created
April 27, 2022 23:44
-
-
Save smx-smx/a29f3c71ab864bb762c6bfb0da1aae67 to your computer and use it in GitHub Desktop.
Binutils GAS file-less frontend
This file contains hidden or 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
/** | |
* @file libgas.c | |
* @author Stefano Moioli <[email protected]> | |
* @brief use GAS from Binutils as a library, without temporary files | |
* this example implements a GAS assembler RAPL - Read Assemble Print Loop | |
* @version 0.1 | |
* @date 2022-04-28 | |
* | |
* @copyright Copyright (c) Stefano Moioli 2022 | |
* | |
*/ | |
#define _GNU_SOURCE | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <fcntl.h> | |
#include <windows.h> | |
#include <sys/stat.h> | |
static HMODULE gas; | |
static void *resolveSymbol(char *sym){ | |
return (void *)GetProcAddress(gas, sym); | |
} | |
#define GVAR(T, sym) T sym = (T)resolveSymbol(#sym) | |
#define GFUNC(ret_type, function, ...) \ | |
ret_type(*function)(__VA_ARGS__) = resolveSymbol(#function) | |
typedef FILE *(*fopen_fn)(const char *filename, const char *mode); | |
typedef void (*appender_fn)(int datum); | |
/** | |
* @brief | |
* the hooked frag_append_1_char declared with --wrap in libgas | |
*/ | |
static appender_fn wrapped_fappend; | |
static void *iovec_open (void *nbfd, void *open_closure){ | |
return open_closure; | |
} | |
static off_t iovec_read( | |
void *nbfd, void *stream, void *buf, | |
off_t nbytes, off_t offset | |
){ | |
unsigned char *mem = (unsigned char *)stream; | |
memcpy(buf, &mem[offset], nbytes); | |
return nbytes; | |
} | |
static void my_fappend(int datum){ | |
printf(">> %02X\n", datum); | |
} | |
int main(int argc, char *argv[]){ | |
setvbuf(stdout, NULL, _IONBF, 0); | |
setvbuf(stderr, NULL, _IONBF, 0); | |
gas = LoadLibraryA("gas-x86_64-unknown-linux.dll"); | |
if(gas == NULL){ | |
fprintf(stderr, "LoadLibraryA failed\n"); | |
return 1; | |
} | |
GFUNC(void, subsegs_begin); | |
GFUNC(void, symbol_begin); | |
GFUNC(void, frag_init); | |
GFUNC(void, elf_begin); | |
GFUNC(void, write_object_file); | |
GFUNC(void, output_file_create, const char *name); | |
GFUNC(void, output_file_close, const char *filename); | |
GFUNC(void *, subseg_new, const char *segname, int subseg); | |
GFUNC(void, bfd_set_section_flags, void *, unsigned); | |
GFUNC(void, subseg_set, void *, int); | |
GFUNC(void, md_begin); | |
GFUNC(void, md_assemble, char *line); | |
GFUNC(void, md_end); | |
GFUNC(void *, bfd_openr_iovec, | |
const char *filename, const char *target, | |
void *(*open) (void *nbfd, void *open_closure), | |
void *open_closure, | |
off_t (*pread) ( | |
void *nbfd, | |
void *stream, void *buf, | |
off_t nbytes, off_t offset), | |
int (*close) (void *nbfd, void *stream), | |
int (*stat) (void *abfd, void *stream, struct stat *sb) | |
); | |
GFUNC(int, bfd_default_set_arch_mach, void *abfd, unsigned arch, unsigned long mach); | |
GFUNC(void, bfd_set_format, void *abfd, int format); | |
GFUNC(int, bfd_close, void *abfd); | |
// address of the fopen function pointer | |
GVAR(fopen_fn *, pfn_fopen); | |
GVAR(appender_fn *, pfn_fappend); | |
GVAR(void **, reg_section); | |
GVAR(void **, expr_section); | |
GVAR(void **, stdoutput); | |
wrapped_fappend = *pfn_fappend; | |
*pfn_fappend = &my_fappend; | |
symbol_begin(); | |
subsegs_begin(); | |
#define MEM_SIZE 1024 * 1024 | |
unsigned char *mem = calloc(MEM_SIZE, 1); | |
/** | |
* create a fake output buffer. | |
* it's actually in read mode, as signaled by the r in "openr" | |
* this will conveniently cause all write operations to be ignored | |
*/ | |
*stdoutput = bfd_openr_iovec( | |
"dummy", NULL, | |
iovec_open, mem, | |
iovec_read, NULL, NULL | |
); | |
// set object format | |
bfd_set_format(*stdoutput, 1); | |
bfd_default_set_arch_mach(*stdoutput, | |
8, // bfd_arch_i386 | |
8 // bfd_mach_x86_64 | |
); | |
/** | |
* create the .text section | |
*/ | |
void *textSeg = subseg_new(".text", 0); | |
bfd_set_section_flags(textSeg, 1 | 2 | 4 | 0x10 |8); | |
subseg_set(textSeg, 0); | |
md_begin(); | |
char *line = NULL; | |
/** | |
* IMPORTANT: md_assemble modifies the input line | |
* so we must always make a copy | |
*/ | |
#define ASM(x) do { \ | |
line = strdup(x); \ | |
md_assemble(line); \ | |
free(line); line = NULL; \ | |
} while(0); | |
char buffer[128]; | |
while(!feof(stdin)){ | |
fgets(buffer, sizeof(buffer), stdin); | |
char *p = strrchr(buffer, '\n'); | |
if(p) *p = '\0'; | |
ASM(buffer); | |
} | |
//ASM("xorl %ebx, %ebx"); | |
if(md_end != NULL){ | |
md_end(); | |
} | |
free(mem); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment