Casio_asm/interpreter/linker.c

157 lines
3.7 KiB
C

#include "linker.h"
int tryLink(string filename, proc_t *proc) {
//variables
source_file_t header;
mapping_t mapping, rom;
int fd;
int pos;
int hasRom=0;
//open the file
fd=File_open(filename, FILE_OPEN_read);
if(fd==-1) {
Platform_setError(LINKER_ERR_NOOPEN);
return 0;
}
pos=0;
//read the header
if(File_read(fd, pos, &header, HEADER_LENGTH)!=HEADER_LENGTH) {
Platform_setError(LINKER_ERR_READ);
File_close(fd);
return 0;
}
pos+=HEADER_LENGTH;
if(header.magic!=MAGIC||header.version!=SOURCE_VERSION) {
Platform_setError(LINKER_ERR_COMPAT);
File_close(fd);
return 0;
}
//read the mappings one by one
for(int i=0; i<header.mappings; i++) {
//read the base mapping
if(File_read(fd, pos, &mapping, MAPPING_LENGTH)!=MAPPING_LENGTH) {
Platform_setError(LINKER_ERR_READ);
File_close(fd);
return 0;
}
pos+=MAPPING_LENGTH;
//map accordingly
if(mapping.type==MAPPING_TYPE_ram) {
//map the RAM in the MMU
if(!Segments_mapRam(&proc->mmu, mapping.offset, mapping.length, mapping.access)) {
Platform_setError(LINKER_ERR_MAP_RAM);
File_close(fd);
return 0;
}
} else if(mapping.type==MAPPING_TYPE_stack) {
//map the stack
if(!Segments_mapStack(&proc->mmu, &proc->stack, mapping.offset, mapping.access)) {
Platform_setError(LINKER_ERR_MAP_STACK);
File_close(fd);
return 0;
}
} else if(mapping.type==MAPPING_TYPE_vram) {
//map the stack
if(!Segments_mapVram(&proc->mmu, mapping.offset)) {
Platform_setError(LINKER_ERR_MAP_VRAM);
File_close(fd);
return 0;
}
} else if(mapping.type==MAPPING_TYPE_file||mapping.type==MAPPING_TYPE_file_raw) {
//read the filename length
char recursive[16];
big_endian_int_t len;
if(File_read(fd, pos, &len, sizeof(big_endian_int_t))!=sizeof(big_endian_int_t)) {
Platform_setError(LINKER_ERR_READ);
File_close(fd);
return 0;
}
pos+=sizeof(big_endian_int_t);
//read the filename
if(File_read(fd, pos, recursive, len.value)!=len.value) {
Platform_setError(LINKER_ERR_READ);
File_close(fd);
return 0;
}
pos+=len.value;
if(mapping.type==MAPPING_TYPE_file) {
//map the file recursively
if(!tryLink(recursive, proc)) {
File_close(fd);
return 0;
}
} else {
//open the file
int flags=0;
if(mapping.access&MAPPING_ACCESS_r) flags|=FILE_OPEN_read;
if(mapping.access&MAPPING_ACCESS_w) flags|=FILE_OPEN_write;
int mapFd=File_open(recursive, flags);
if(mapFd==-1) {
Platform_setError(LINKER_ERR_NOOPEN);
File_close(fd);
return 0;
}
//map the file directly
if(!Segments_mapFile(&proc->mmu, fd, mapping.offset, mapping.length, 0, mapping.access)) {
Platform_setError(LINKER_ERR_MAP_FILE);
File_close(mapFd);
File_close(fd);
return 0;
}
}
} else if(mapping.type==MAPPING_TYPE_rom) {
//check if we already have a ROM mapping
if(hasRom) {
Platform_setError(LINKER_ERR_DUPROM);
File_close(fd);
return 0;
}
//store this for later
rom=mapping;
hasRom=1;
}
}
//map the ROM if present
if(hasRom) {
//open the ROM correctly
if(rom.access&MAPPING_ACCESS_w) {
File_close(fd);
fd=File_open(filename, FILE_OPEN_read|FILE_OPEN_write);
if(fd==-1) {
Platform_setError(LINKER_ERR_NOOPEN);
return 0;
}
}
//map the ROM
if(!Segments_mapFile(&proc->mmu, fd, rom.offset, rom.length, pos, rom.access)) {
Platform_setError(LINKER_ERR_MAP_ROM);
File_close(fd);
return 0;
}
} else {
//close the file
File_close(fd);
}
//setup the entry point and return
proc->registers[0].i=header.entryPoint;
return 1;
}
int Linker_link(string filename, proc_t *proc) {
if(!tryLink(filename, proc)) {
Segments_unmapAll(&proc->mmu);
return 0;
}
return 1;
}