ELF: added support for SHT_RISCV_ATTRIBUTES seg

master
vhaudiquet 11 months ago
parent 326b52ef86
commit a0935f0aad
  1. 166
      src/bootloader/elf/elf.c
  2. 1
      src/bootloader/elf/elf.h

@ -8,94 +8,98 @@
uint32_t elf_32_load(void* file) uint32_t elf_32_load(void* file)
{ {
// Parse/verify the header // Parse/verify the header
elf_header_32_t* header = file; elf_header_32_t* header = file;
// Verify magic number // Verify magic number
uint8_t* m = header->ELF; uint8_t* m = header->ELF;
if((m[0] != 0x7F) || (m[1] != 'E') || (m[2] != 'L') || (m[3] != 'F')) if((m[0] != 0x7F) || (m[1] != 'E') || (m[2] != 'L') || (m[3] != 'F'))
{ {
fprintf(stderr, "Not a valid ELF file (wrong magic)\n"); fprintf(stderr, "Not a valid ELF file (wrong magic)\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
// Verify architecture // Verify architecture
if(header->instruction_set != INSTRUCTION_SET_RISCV) if(header->instruction_set != INSTRUCTION_SET_RISCV)
{ {
switch(header->instruction_set) switch(header->instruction_set)
{ {
case INSTRUCTION_SET_X86: case INSTRUCTION_SET_X86:
fprintf(stderr, "Provided ELF file targets x86 ; perhaps you forgot to cross-compile ? Please provide a RISC-V ELF\n"); fprintf(stderr, "Provided ELF file targets x86 ; perhaps you forgot to cross-compile ? Please provide a RISC-V ELF\n");
break; break;
case INSTRUCTION_SET_X86_64: case INSTRUCTION_SET_X86_64:
fprintf(stderr, "Provided ELF file targets x86_64; perhaps you forgot to cross-compile ? Please provide a RISC-V ELF\n"); fprintf(stderr, "Provided ELF file targets x86_64; perhaps you forgot to cross-compile ? Please provide a RISC-V ELF\n");
break; break;
default: default:
fprintf(stderr, "Provided ELF file is for an unknown instruction set architecture (0x%x), please provide a RISC-V ELF\n", header->instruction_set); fprintf(stderr, "Provided ELF file is for an unknown instruction set architecture (0x%x), please provide a RISC-V ELF\n", header->instruction_set);
break; break;
} }
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
// Verify bit count // Verify bit count
if(header->bits != BITS_32) if(header->bits != BITS_32)
{ {
switch(header->bits) switch(header->bits)
{ {
case BITS_64: case BITS_64:
fprintf(stderr, "Provided ELF file targets RISC-V 64 bits ; please provide a 32-bits ELF\n"); fprintf(stderr, "Provided ELF file targets RISC-V 64 bits ; please provide a 32-bits ELF\n");
break; break;
default: default:
fprintf(stderr, "Provided ELF file targets an unknown bit count (not 32 bits) ; please provide a 32-bits ELF\n"); fprintf(stderr, "Provided ELF file targets an unknown bit count (not 32 bits) ; please provide a 32-bits ELF\n");
break; break;
} }
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
// Verify endianness // Verify endianness
if(header->endianness != ELF_LITTLE_ENDIAN) if(header->endianness != ELF_LITTLE_ENDIAN)
{ {
fprintf(stderr, "Provided ELF file is encoded in big endian ; please provide a little endian ELF\n"); fprintf(stderr, "Provided ELF file is encoded in big endian ; please provide a little endian ELF\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
// File should be correct ; now load it, using program header table // File should be correct ; now load it, using program header table
elf_program_header_32_t* program_header = (elf_program_header_32_t*) (((uint8_t*) file) + header->program_header_table_32); elf_program_header_32_t* program_header = (elf_program_header_32_t*) (((uint8_t*) file) + header->program_header_table_32);
size_t program_header_count = header->program_entry_amount; size_t program_header_count = header->program_entry_amount;
for(size_t i = 0; i < program_header_count; i++) for(size_t i = 0; i < program_header_count; i++)
{ {
elf_program_header_32_t current = program_header[i]; elf_program_header_32_t current = program_header[i];
// Check segment type // Check segment type
if(current.segment_type != SEGMENT_TYPE_LOAD) if(current.segment_type != SEGMENT_TYPE_LOAD)
{ {
fprintf(stderr, "WARNING: Unknown segment type %u in ELF file ; skipping\n", current.segment_type); // Don't message for riscv-specific attributes segment
continue; if(current.segment_type != SEGMENT_TYPE_RISCV_SPECIFIC_SHT_RISCV_ATTRIBUTES)
} {
fprintf(stderr, "WARNING: Unknown segment type %u in ELF file ; skipping\n", current.segment_type);
}
continue;
}
// Check memory size // Check memory size
size_t memsz = current.segment_memory_size; size_t memsz = current.segment_memory_size;
if(!memsz) if(!memsz)
{ {
fprintf(stderr, "WARNING: LOAD segment with null size in ELF file ; skipping\n"); fprintf(stderr, "WARNING: LOAD segment with null size in ELF file ; skipping\n");
continue; continue;
} }
// Map the segment : first the part in the file, then the zeros // Map the segment : first the part in the file, then the zeros
if(memory_size < (current.virtual_address + memsz)) if(memory_size < (current.virtual_address + memsz))
{ {
fprintf(stderr, "FATAL: Not enough memory while loading ELF file\n"); fprintf(stderr, "FATAL: Not enough memory while loading ELF file\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if(current.segment_file_size != 0) if(current.segment_file_size != 0)
{ {
memcpy(&memory[current.virtual_address], ((uint8_t*) file) + current.segment_offset, current.segment_file_size); memcpy(&memory[current.virtual_address], ((uint8_t*) file) + current.segment_offset, current.segment_file_size);
} }
if(memsz > current.segment_file_size) if(memsz > current.segment_file_size)
{ {
memset(&memory[current.virtual_address] + current.segment_file_size, 0, memsz - current.segment_file_size); memset(&memory[current.virtual_address] + current.segment_file_size, 0, memsz - current.segment_file_size);
} }
} }
return header->entry_32; return header->entry_32;
} }

@ -77,6 +77,7 @@ typedef struct ELF_PROGRAM_HEADER_32
#define SEGMENT_TYPE_DYNAMIC 2 #define SEGMENT_TYPE_DYNAMIC 2
#define SEGMENT_TYPE_INTERP 3 #define SEGMENT_TYPE_INTERP 3
#define SEGMENT_TYPE_NOTE 4 #define SEGMENT_TYPE_NOTE 4
#define SEGMENT_TYPE_RISCV_SPECIFIC_SHT_RISCV_ATTRIBUTES 0x70000003
uint32_t elf_32_load(void* file); uint32_t elf_32_load(void* file);

Loading…
Cancel
Save