157 lines
3.7 KiB
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;
|
|
}
|