#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; immu, 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; }