170 lines
3 KiB
C
170 lines
3 KiB
C
#include <unistd.h>
|
|
#include <merror.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
|
|
#include "gen.h"
|
|
#include "masm.h"
|
|
#include "asm/elf32.h"
|
|
|
|
void help(void) {
|
|
printf(
|
|
"usage: masm [options] source.asm\n"
|
|
"\n"
|
|
"options: \n"
|
|
" -h print the help message \n"
|
|
" -g assume undefined symbols are external\n"
|
|
" -o <output> specify the object file output name \n"
|
|
" -a <abi> specify mips abi used [none, o32] \n"
|
|
" default: o32 \n"
|
|
" -i <isa> mips machine isa to assemble for [mips1, mips32r2, mips32r6] \n"
|
|
" default: mips32r6\n"
|
|
" -f <format> specify the object file format [elf32] \n"
|
|
" defualt: elf32\n"
|
|
);
|
|
}
|
|
|
|
static int read_isa(enum isa *isa, const char *str)
|
|
{
|
|
#define __ISA_CHK(name) \
|
|
if (strcasecmp(#name, str) == 0) { \
|
|
*isa = ISA_ ##name; \
|
|
return M_SUCCESS; \
|
|
} \
|
|
|
|
__ISA_CHK(MIPS1);
|
|
__ISA_CHK(MIPS32R2);
|
|
__ISA_CHK(MIPS32R6);
|
|
|
|
ERROR("invalid isa '%s'", str);
|
|
return M_ERROR;
|
|
}
|
|
|
|
static int read_abi(enum abi *abi, const char *str)
|
|
{
|
|
#define __ABI_CHK(name) \
|
|
if (strcasecmp(#name, str) == 0) { \
|
|
*abi = ABI_ ##name; \
|
|
return M_SUCCESS; \
|
|
} \
|
|
|
|
|
|
__ABI_CHK(O32);
|
|
__ABI_CHK(NONE);
|
|
|
|
ERROR("invalid abi '%s'", str);
|
|
return M_ERROR;
|
|
}
|
|
|
|
static int read_format(enum format *format, const char *str)
|
|
{
|
|
#define __FORMAT_CHK(name) \
|
|
if (strcasecmp(#name, str) == 0) { \
|
|
*format = FORMAT_ ##name; \
|
|
return M_SUCCESS; \
|
|
} \
|
|
|
|
|
|
__FORMAT_CHK(ELF32);
|
|
|
|
ERROR("invalid format '%s'", str);
|
|
return M_ERROR;
|
|
}
|
|
|
|
static int generate(struct generator *gen, struct arguments *args)
|
|
{
|
|
if (generator_init(args->in_file, gen))
|
|
return M_ERROR;
|
|
|
|
switch (args->isa) {
|
|
case ISA_MIPS1:
|
|
return generate_mips1(gen);
|
|
case ISA_MIPS32R2:
|
|
return generate_mips32r2(gen);
|
|
case ISA_MIPS32R6:
|
|
return generate_mips32r6(gen);
|
|
}
|
|
|
|
return M_ERROR;
|
|
}
|
|
|
|
static int assemble(struct arguments *args)
|
|
{
|
|
struct generator gen;
|
|
int res = M_SUCCESS;
|
|
|
|
if (generate(&gen, args))
|
|
return M_ERROR;
|
|
|
|
switch (args->format) {
|
|
case FORMAT_ELF32:
|
|
res = assemble_elf32(&gen, args);
|
|
break;
|
|
default:
|
|
res = M_ERROR;
|
|
break;
|
|
}
|
|
|
|
generator_free(&gen);
|
|
|
|
return res;
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
|
|
struct arguments args = {
|
|
.in_file = NULL,
|
|
.out_file = "out.o",
|
|
.extern_undefined = false,
|
|
.isa = ISA_MIPS32R6,
|
|
.abi = ABI_O32,
|
|
.format = FORMAT_ELF32
|
|
};
|
|
|
|
int c;
|
|
|
|
while ((c = getopt(argc, argv, "hgo:a:i:f:")) != 1) {
|
|
switch(c) {
|
|
case 'h':
|
|
help();
|
|
return M_SUCCESS;
|
|
case 'g':
|
|
args.extern_undefined = true;
|
|
break;
|
|
case 'o':
|
|
args.out_file = optarg;
|
|
break;
|
|
case 'a':
|
|
if (read_abi(&args.abi, optarg))
|
|
return M_ERROR;
|
|
break;
|
|
case 'i':
|
|
if (read_isa(&args.isa, optarg))
|
|
return M_ERROR;
|
|
break;
|
|
case 'f':
|
|
if (read_format(&args.format, optarg))
|
|
return M_ERROR;
|
|
break;
|
|
case '?':
|
|
return M_ERROR;
|
|
default:
|
|
goto next;
|
|
}
|
|
}
|
|
|
|
next:
|
|
if (optind < argc - 1) {
|
|
ERROR("too many source files passed");
|
|
return M_ERROR;
|
|
}
|
|
|
|
if (optind >= argc) {
|
|
ERROR("no source files passed");
|
|
return M_ERROR;
|
|
}
|
|
|
|
args.in_file = argv[optind];
|
|
|
|
return assemble(&args);
|
|
}
|