Guest User

M68k ELF loader function

a guest
Nov 13th, 2024
36
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 9.07 KB | None | 0 0
  1. #include <stdint.h>
  2. #include "elf.h"
  3.  
  4. uint32_t loadELF(uint8_t fd, uint32_t *entry){
  5.     /* ELF headers/structs */
  6.     Elf32_Ehdr ehdr;
  7.     Elf32_Phdr phdr;
  8.     Elf32_Dyn dyn;
  9.    
  10.     /* Relocation variables/structs */
  11.     Elf32_Rela *rela_ptr;
  12.     uint32_t rela_count;
  13.     uint32_t rela_size = 0;
  14.     Elf32_Sym *sym_ptr;
  15.     uint32_t sym_size = 0;
  16.     uint32_t sym_val;
  17.    
  18.     uint32_t tmp;
  19.    
  20.     uint32_t total_mem_size = 0;
  21.     uint32_t virtual_base_addr = 0xFFFFFFFF;
  22.     uint32_t physical_base_addr;
  23.    
  24.    
  25.     /* Move the pointer to the start of the File, just in case */
  26.     SYSCALL_seekFile(fd, 0, SEEK_SET);
  27.    
  28.     if(SYSCALL_readFile(fd, &ehdr, sizeof(Elf32_Ehdr)) != sizeof(Elf32_Ehdr)){
  29.         dbg_printf("Failed to read ELF header\n");
  30.         SYSCALL_closeFile(fd);
  31.         return 0;
  32.     }
  33.    
  34.     if((memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0) ||  /* Check ELF magic number */
  35.         (ehdr.e_ident[EI_CLASS] != ELFCLASS32) ||       /* Check ELF class (32-bit) */
  36.         (ehdr.e_ident[EI_DATA] != ELFDATA2MSB) ||       /* Check data encoding (big-endian) */
  37.         (ehdr.e_ident[EI_VERSION] != EV_CURRENT) ||     /* Check ELF version */
  38.         (ehdr.e_machine != EM_M68K) ||                  /* Check target architecture (Motorola 68000) */
  39.         (ehdr.e_type != ET_EXEC)){                      /* Check file type (executable) */
  40.        
  41.         dbg_printf("Invalid ELF header\n");
  42.         SYSCALL_closeFile(fd);
  43.         return 0;
  44.     }
  45.    
  46.    
  47.     for(uint32_t i = 0; i < ehdr.e_phnum; i++){
  48.        
  49.         /* Read each program header */
  50.         // dbg_printf("Reading program header %lu from offset %lu in the file\n", i, ehdr.e_phoff + (i * sizeof(Elf32_Phdr)));
  51.         SYSCALL_seekFile(fd, ehdr.e_phoff + (i * sizeof(Elf32_Phdr)), SEEK_SET);
  52.         if(SYSCALL_readFile(fd, &phdr, sizeof(Elf32_Phdr)) != sizeof(Elf32_Phdr)){
  53.             dbg_printf("Failed to read program header %lu\n", i);
  54.             SYSCALL_closeFile(fd);
  55.             return 0;
  56.         }
  57.        
  58.         /* If the segment is loadable, calculate memory size and find the base address */
  59.         if(phdr.p_type == PT_LOAD){
  60.             dbg_printf("Found loadable segment: vaddr = 0x%08lX, memsz = 0x%08lX\n", phdr.p_vaddr, phdr.p_memsz);
  61.             total_mem_size += phdr.p_memsz;
  62.             if((phdr.p_vaddr) < virtual_base_addr){
  63.                 virtual_base_addr = phdr.p_vaddr;
  64.             }
  65.         }
  66.     }
  67.    
  68.     /* Allocate the required Memory */
  69.     physical_base_addr = (uint32_t)allocMem(total_mem_size, currentTask);
  70.    
  71.     if(!physical_base_addr){
  72.         dbg_printf("Failed to allocate %luB for executable\n", total_mem_size);
  73.         SYSCALL_closeFile(fd);
  74.         return 0;
  75.     }
  76.    
  77.     dbg_printf("Total amount of Memory: %luB\nVirtual/Physical Base Addresses: 0x%08lX/0x%08lX\n", total_mem_size, virtual_base_addr, physical_base_addr);
  78.    
  79.     /* Load each loadable segment into memory */
  80.     for(uint32_t i = 0; i < ehdr.e_phnum; i++){
  81.        
  82.         /* Read each program header again */
  83.         // dbg_printf("Reading program header %lu from offset %lu in the file\n", i, ehdr.e_phoff + (i * sizeof(Elf32_Phdr)));
  84.         SYSCALL_seekFile(fd, ehdr.e_phoff + (i * sizeof(Elf32_Phdr)), SEEK_SET);
  85.         if(SYSCALL_readFile(fd, &phdr, sizeof(Elf32_Phdr)) != sizeof(Elf32_Phdr)){
  86.             dbg_printf("Failed to read program header %lu\n", i);
  87.            
  88.             SYSCALL_closeFile(fd);
  89.            
  90.             freeMem((void*)physical_base_addr);
  91.            
  92.             return 0;
  93.         }
  94.        
  95.         /* If the segment is not loadable, skip it */
  96.         if(phdr.p_type != PT_LOAD) continue;
  97.        
  98.         dbg_printf("Loading segment %lu from offset %lu in the file\n", i, phdr.p_offset);
  99.        
  100.         SYSCALL_seekFile(fd, phdr.p_offset, SEEK_SET);
  101.         if(SYSCALL_readFile(fd, (uint8_t*)RELOC(phdr.p_vaddr), phdr.p_filesz) != phdr.p_filesz){
  102.             dbg_printf("Failed to load segment %lu\n", i);
  103.            
  104.             SYSCALL_closeFile(fd);
  105.            
  106.             freeMem((void*)physical_base_addr);
  107.            
  108.             return 0;
  109.         }
  110.        
  111.         dbg_printf("Loaded segment\n");
  112.        
  113.         // Zero out the remaining memory if p_memsz > p_filesz
  114.         if(phdr.p_memsz > phdr.p_filesz){
  115.             memset((uint8_t*)(RELOC(phdr.p_vaddr) + phdr.p_filesz), 0, phdr.p_memsz - phdr.p_filesz);
  116.         }
  117.     }
  118.    
  119.     /* Process relocation entries if necessary */
  120.     if(physical_base_addr == virtual_base_addr) goto noreloc;
  121.    
  122.     for(uint32_t i = 0; i < ehdr.e_phnum; i++){
  123.        
  124.         /* Read each program header again again */
  125.         dbg_printf("Reading program header %lu from offset %lu in the file\n", i, ehdr.e_phoff + (i * sizeof(Elf32_Phdr)));
  126.         SYSCALL_seekFile(fd, ehdr.e_phoff + (i * sizeof(Elf32_Phdr)), SEEK_SET);
  127.         if(SYSCALL_readFile(fd, &phdr, sizeof(Elf32_Phdr)) != sizeof(Elf32_Phdr)){
  128.             dbg_printf("Failed to read program header %lu\n", i);
  129.             SYSCALL_closeFile(fd);
  130.             freeMem((void*)physical_base_addr);
  131.             return 0;
  132.         }
  133.        
  134.         /* If the segment is not dynamic, skip it */
  135.         if(phdr.p_type != PT_DYNAMIC) continue;
  136.        
  137.         for(uint32_t j = 0; j < (phdr.p_memsz / sizeof(Elf32_Dyn)); j++){
  138.            
  139.             // dbg_printf("reading dynamic header %lu/%lu from offset %lu in the file\n", j, (phdr.p_memsz / sizeof(Elf32_Dyn)), phdr.p_offset + (j * sizeof(Elf32_Dyn)));
  140.             SYSCALL_seekFile(fd, phdr.p_offset + (j * sizeof(Elf32_Dyn)), SEEK_SET);
  141.             if(SYSCALL_readFile(fd, &dyn, sizeof(Elf32_Dyn)) != sizeof(Elf32_Dyn)){
  142.                 dbg_printf("Failed to read dynamic section entry %lu\n", j);
  143.                 SYSCALL_closeFile(fd);
  144.                 freeMem((void*)physical_base_addr);
  145.                 return 0;
  146.             }
  147.            
  148.             /* Process relocation entries */
  149.             switch(dyn.d_tag){
  150.                 case DT_NULL:       // End of the list
  151.                    
  152.                 goto dyn_exit;
  153.                
  154.                 case DT_SYMTAB:     // Symbol Table Address
  155.                     dbg_printf("SYMTAB, 0x%08lX\n", dyn.d_un.d_ptr);
  156.                     sym_ptr = (Elf32_Sym*)(RELOC(dyn.d_un.d_ptr));
  157.                 break;
  158.                
  159.                 case DT_SYMENT:     // Symbol Table Size
  160.                     dbg_printf("SYMENT, %lu\n", dyn.d_un.d_val);
  161.                     sym_size = dyn.d_un.d_val;
  162.                 break;
  163.                
  164.                 case DT_RELA:       // Relocation (addend) Table Address
  165.                     dbg_printf("RELA, 0x%08lX\n", dyn.d_un.d_ptr);
  166.                     rela_ptr = (Elf32_Rela*)(RELOC(dyn.d_un.d_ptr));
  167.                 break;
  168.                
  169.                 case DT_RELASZ:     // Relocation (addend) Table Size
  170.                     dbg_printf("RELASZ, %lu\n", dyn.d_un.d_val);
  171.                     rela_count = dyn.d_un.d_val;
  172.                 break;
  173.                
  174.                 case DT_RELAENT:    // Relocation (addend) Entry Size
  175.                     dbg_printf("RELAENT, %lu\n", dyn.d_un.d_val);
  176.                     rela_size = dyn.d_un.d_val;
  177.                 break;
  178.                
  179.                 default:
  180.                     /*
  181.                     if(dyn.d_tag > 33){
  182.                         dbg_printf("Unhandled dynamic entry, d_tag: 0x%08lX\n", dyn.d_tag);
  183.                     }else{
  184.                         dbg_printf("Unhandled dynamic entry, d_tag: %lu\n", dyn.d_tag);
  185.                     }
  186.                     */
  187.                 break;
  188.             }
  189.         }
  190.     }
  191.     /* The exit being here assumes there is only ever 1 Dynamic Segment */
  192.     dyn_exit:
  193.    
  194.    
  195.     /* Actually apply the relocation (if any were present) */
  196.     if(rela_size == 0) goto noreloc;
  197.    
  198.     dbg_printf("Handle Relocation Types\n");
  199.     for(uint32_t i = 0; i < (rela_count / rela_size); i++){
  200.        
  201.        
  202.         /* Handle the different relocation types */
  203.         switch(ELF32_R_TYPE(rela_ptr[i].r_info)){
  204.            
  205.             /*
  206.                 r_offset is the virtual address of the 32-bit word that needs relocation
  207.                 physical address = (r_offset - virtual_base_addr) + physical_base_addr
  208.                
  209.                 r_addend is the value that needs to be relocated and written to the physical address of r_offset
  210.                 value = (r_addend - virtual_base_addr) + physical_base_addr
  211.             */
  212.             case R_68K_RELATIVE:
  213.                 tmp = mread32(RELOC(rela_ptr[i].r_offset));
  214.                 dbg_printf("Address: 0x%08lX (Old/New Values: 0x%08lX/0x%08lX) (R_68K_RELATIVE)\n", RELOC(rela_ptr[i].r_offset), tmp, RELOC(rela_ptr[i].r_addend));
  215.                 mwrite32(RELOC(rela_ptr[i].r_offset), RELOC(rela_ptr[i].r_addend));
  216.             break;
  217.            
  218.             /*
  219.                 32 is Similar to RELATIVE, but with a symbol that gets added to r_addend before relocation
  220.             */
  221.             case R_68K_32:
  222.                 sym_val = sym_ptr[ELF32_R_SYM(rela_ptr[i].r_info)].st_value;
  223.                
  224.                 tmp = mread32(RELOC(rela_ptr[i].r_offset));
  225.                 dbg_printf("Address: 0x%08lX (Old/New Values: 0x%08lX/0x%08lX) (R_68K_32)\n", RELOC(rela_ptr[i].r_offset), tmp, RELOC((rela_ptr[i].r_addend + sym_val)));
  226.                
  227.                 mwrite32(RELOC(rela_ptr[i].r_offset), RELOC((rela_ptr[i].r_addend + sym_val)));
  228.             break;
  229.            
  230.             /*
  231.                 Same as 32, but with a 16-bit word
  232.             */
  233.             case R_68K_16:
  234.                 sym_val = sym_ptr[ELF32_R_SYM(rela_ptr[i].r_info)].st_value;
  235.                
  236.                 tmp = mread16(RELOC(rela_ptr[i].r_offset));
  237.                 dbg_printf("Address: 0x%08lX (Old/New Values: 0x%08X/0x%08X) (R_68K_16)\n", RELOC(rela_ptr[i].r_offset), (uint16_t)tmp, (uint16_t)(RELOC((rela_ptr[i].r_addend + sym_val)) & 0x0000FFFF));
  238.                
  239.                 mwrite16(RELOC(rela_ptr[i].r_offset), RELOC((rela_ptr[i].r_addend + sym_val)) & 0x0000FFFF);
  240.             break;
  241.            
  242.             /*
  243.                 Same as 32, but with a 8-bit byte
  244.             */
  245.             case R_68K_8:
  246.                 sym_val = sym_ptr[ELF32_R_SYM(rela_ptr[i].r_info)].st_value;
  247.                
  248.                 tmp = mread8(RELOC(rela_ptr[i].r_offset));
  249.                 dbg_printf("Address: 0x%08lX (Old/New Values: 0x%08X/0x%08X) (R_68K_8)\n", RELOC(rela_ptr[i].r_offset), (uint8_t)tmp, (uint8_t)(RELOC((rela_ptr[i].r_addend + sym_val)) & 0x000000FF));
  250.                
  251.                 mwrite8(RELOC(rela_ptr[i].r_offset), RELOC((rela_ptr[i].r_addend + sym_val)) & 0x000000FF);
  252.             break;
  253.            
  254.             default:
  255.                 dbg_printf("Unhandled relocation type: %lu\n", ELF32_R_TYPE(rela_ptr[i].r_info));
  256.             break;
  257.         }
  258.        
  259.     }
  260.     noreloc:
  261.    
  262.     /* Update the entry point address */
  263.     *entry = RELOC((uint32_t)ehdr.e_entry);
  264.    
  265.     dbg_printf("Entry point set to: 0x%08lX\n", *entry);
  266.    
  267.     /* Close the file and return */
  268.     SYSCALL_closeFile(fd);
  269.     return physical_base_addr;
  270. }
Advertisement
Add Comment
Please, Sign In to add comment