static unsafe byte *ReadStructure(lib.File s, long pos, long len) { byte[] ret = new byte[len]; s.Seek(pos, System.IO.SeekOrigin.Begin); int bytes_read = s.Read(ret, 0, (int)len); if (bytes_read != len) { throw new Exception("ReadStructure: read " + bytes_read.ToString() + "bytes, expected " + len.ToString()); } return((byte *)libsupcs.MemoryOperations.GetInternalArray(ret)); }
static int Read(lib.File handle, byte[] dest, int dest_offset, int count, out MonoIOError error) { Formatter.Write("MonoIO.Read: called (handle: ", Program.arch.DebugOutput); Formatter.Write((ulong)libsupcs.CastOperations.ReinterpretAsUlong(handle), "X", Program.arch.DebugOutput); Formatter.Write(" dest_offset: ", Program.arch.DebugOutput); Formatter.Write((ulong)dest_offset, Program.arch.DebugOutput); Formatter.Write(" count: ", Program.arch.DebugOutput); Formatter.Write((ulong)count, Program.arch.DebugOutput); Formatter.WriteLine(")", Program.arch.DebugOutput); if (handle == null) { error = MonoIOError.ERROR_INVALID_HANDLE; return(-1); } int ret = handle.Read(dest, dest_offset, count); error = handle.Error; return(ret); }
static uint ReadUInt32(lib.File s) { byte[] val = new byte[4]; s.Read(val, 0, 4); return(BitConverter.ToUInt32(val, 0)); }
static long ReadInt64(lib.File s) { byte[] val = new byte[8]; s.Read(val, 0, 8); return(BitConverter.ToInt64(val, 0)); }
public static unsafe ulong LoadObject(Virtual_Regions vreg, VirtMem vmem, SymbolTable stab, lib.File s, string name, out ulong tls_size) { ElfReader.Elf64_Ehdr ehdr = ReadHeader(s); /* Load up section headers */ ulong e_shentsize = ehdr.e_shentsize; byte *shdrs = ReadStructure(s, ehdr.e_shoff, ehdr.e_shnum * e_shentsize); /* Load up section string table */ ElfReader.Elf64_Shdr *shdr_shstr = (ElfReader.Elf64_Shdr *)(shdrs + ehdr.e_shstrndx * e_shentsize); byte *sect_shstr = ReadStructure(s, shdr_shstr->sh_offset, shdr_shstr->sh_size); /* Iterate through the sections marked SHF_ALLOC, allocating space as we go */ uint e_shnum = (uint)ehdr.e_shnum; byte *sect_header = shdrs; /* .to files are relocatable but have the entry point set anyway */ ulong text_section = 0; ulong hdr_epoint = ehdr.e_entry; ulong hash_section = 0; ulong hash_len = 0; ElfReader.Elf64_Shdr *sym_tab_hdr = null; ElfReader.Elf64_Shdr *sym_tab_str_hdr = null; /* Map sections to their load address */ Dictionary <uint, ulong> sect_map = new Dictionary <uint, ulong>(); ulong start = 0; tls_size = Program.arch.tysos_tls_length; for (uint i = 0; i < e_shnum; i++) { ElfReader.Elf64_Shdr *cur_shdr = (ElfReader.Elf64_Shdr *)sect_header; // if this .symtab? if (cur_shdr->sh_type == 0x2) { sym_tab_hdr = cur_shdr; if (cur_shdr->sh_link != 0) { sym_tab_str_hdr = (ElfReader.Elf64_Shdr *)(shdrs + cur_shdr->sh_link * e_shentsize); } } if ((cur_shdr->sh_flags & 0x2) == 0x2) { /* SHF_ALLOC */ if ((cur_shdr->sh_flags & (1 << 10)) != 0) { // TLS tls_size += cur_shdr->sh_size; continue; } // get its name byte * name_addr = sect_shstr + cur_shdr->sh_name; string sect_name = new string((sbyte *)name_addr); /* Register with gc if writeable and not executable */ bool gc_data = false; if (((cur_shdr->sh_flags & 0x1) != 0) && ((cur_shdr->sh_flags & 0x4) == 0)) { gc_data = true; } // allocate space for it ulong sect_addr = vreg.AllocRegion(cur_shdr->sh_size, 0x1000, name + sect_name, 0, Virtual_Regions.Region.RegionType.ModuleSection, gc_data).start; cur_shdr->sh_addr = sect_addr; sect_map[i] = sect_addr; if (sect_addr + cur_shdr->sh_size > 0x7effffffff) { throw new Exception("Object section allocated beyond limit of small code model"); } // is this .text? if (sect_name == ".text") { text_section = sect_addr; } // or .hash? if (sect_name == ".hash") { hash_section = sect_addr; hash_len = cur_shdr->sh_size; } // copy the section to its destination if (cur_shdr->sh_type == 0x1) { /* SHT_PROGBITS */ // Convert the VirtualRegion to a managed byte array //byte[] sect_data = libsupcs.TysosArrayType.CreateByteArray((byte*)sect_addr, (int)cur_shdr->sh_size); byte[] sect_data = libsupcs.Array.CreateSZArray <byte>((int)cur_shdr->sh_size, (void *)sect_addr); System.Diagnostics.Debugger.Log(0, null, "ElfFileReader.LoadObject: begin loading section data"); // Read the section data into it s.Seek((long)cur_shdr->sh_offset, System.IO.SeekOrigin.Begin); s.Read(sect_data, 0, (int)cur_shdr->sh_size); System.Diagnostics.Debugger.Log(0, null, "ElfFileReader.LoadObject: end loading section data"); } else if (cur_shdr->sh_type == 0x8) { /* SHT_NOBITS */ System.Diagnostics.Debugger.Log(0, null, "ElfFileReader.LoadObject: begin clearing blank section"); libsupcs.MemoryOperations.MemSet((void *)sect_addr, 0, (int)cur_shdr->sh_size); System.Diagnostics.Debugger.Log(0, null, "ElfFileReader.LoadObject: end clearing blank section"); } } sect_header += e_shentsize; } if (hash_section != 0 && hash_len != 0 && sym_tab_hdr != null && sym_tab_str_hdr != null) { // Load symbol table and hash table System.Diagnostics.Debugger.Log(0, null, "ElfFileReader.LoadObject: begin loading symbol table"); var sym_data = ReadStructure(s, sym_tab_hdr->sh_offset, sym_tab_hdr->sh_size); sym_tab_hdr->sh_addr = (ulong)sym_data; System.Diagnostics.Debugger.Log(0, null, "ElfFileReader.LoadObject: end loading symbol table"); System.Diagnostics.Debugger.Log(0, null, "ElfFileReader.LoadObject: begin loading symbol string table"); var sym_str_data = ReadStructure(s, sym_tab_str_hdr->sh_offset, sym_tab_str_hdr->sh_size); sym_tab_str_hdr->sh_addr = (ulong)sym_str_data; System.Diagnostics.Debugger.Log(0, null, "ElfFileReader.LoadObject: end loading symbol string table"); System.Diagnostics.Debugger.Log(0, null, "ElfFileReader.LoadObject: begin loading hash symbol section"); var ht = new ElfReader.ElfHashTable(hash_section, (ulong)sym_data, sym_tab_hdr->sh_entsize, (ulong)sym_str_data, sect_map, (int)sym_tab_hdr->sh_info, sym_tab_hdr->sh_size); stab.symbol_providers.Add(ht); System.Diagnostics.Debugger.Log(0, null, "ElfFileReader.LoadObject: end loading hash symbol section"); } else { System.Diagnostics.Debugger.Log(0, null, "ElfFileReader.LoadObject: begin loading symbols"); /* Iterate through defined symbols, loading them into the symbol table */ sect_header = shdrs; for (uint i = 0; i < e_shnum; i++) { ElfReader.Elf64_Shdr *cur_shdr = (ElfReader.Elf64_Shdr *)sect_header; if (cur_shdr->sh_type == 0x2) { /* SHT_SYMTAB */ // Load up the section data byte *shdr_data = ReadStructure(s, cur_shdr->sh_offset, cur_shdr->sh_size); ulong offset = cur_shdr->sh_info * cur_shdr->sh_entsize; cur_shdr->sh_addr = (ulong)shdr_data; while (offset < cur_shdr->sh_size) { ElfReader.Elf64_Sym *cur_sym = (ElfReader.Elf64_Sym *)(shdr_data + offset); bool is_vis = false; bool is_weak = false; uint st_bind = (cur_sym->st_info_other_shndx >> 4) & 0xf; if (st_bind == 1) { // STB_GLOBAL is_vis = true; } else if (st_bind == 2) { // STB_WEAK is_vis = true; is_weak = true; } if (is_vis) { /* Get the symbol's name */ // If the appropriate string table is not loaded, then load it ElfReader.Elf64_Shdr *strtab = (ElfReader.Elf64_Shdr *)(shdrs + cur_shdr->sh_link * e_shentsize); if (strtab->sh_addr == 0) { strtab->sh_addr = (ulong)ReadStructure(s, strtab->sh_offset, strtab->sh_size); } // Get the name string sym_name = new string((sbyte *)(strtab->sh_addr + cur_sym->st_name)); uint st_shndx = (cur_sym->st_info_other_shndx >> 16) & 0xffff; if (st_shndx != 0) { if (is_weak == false || stab.GetAddress(sym_name) == 0) { ulong sym_addr = ((ElfReader.Elf64_Shdr *)(shdrs + st_shndx * e_shentsize))->sh_addr + cur_sym->st_value; if (sym_name == "_start") { start = sym_addr; } else { stab.Add(sym_name, sym_addr, cur_sym->st_size); } } } } offset += cur_shdr->sh_entsize; } } sect_header += e_shentsize; } System.Diagnostics.Debugger.Log(0, null, "ElfFileReader.LoadObject: end loading symbols"); } System.Diagnostics.Debugger.Log(0, null, "ElfFileReader.LoadObject: begin fixing relocations"); /* Iterate through relocations, fixing them up as we go */ sect_header = shdrs; for (uint i = 0; i < e_shnum; i++) { ElfReader.Elf64_Shdr *cur_shdr = (ElfReader.Elf64_Shdr *)sect_header; if (cur_shdr->sh_type == 0x9) { throw new NotImplementedException("rel sections not supported"); } if (cur_shdr->sh_type == 0x4) { /* SHT_RELA */ ElfReader.Elf64_Shdr *cur_symtab = (ElfReader.Elf64_Shdr *)(shdrs + cur_shdr->sh_link * e_shentsize); ElfReader.Elf64_Shdr *rela_sect = (ElfReader.Elf64_Shdr *)(shdrs + cur_shdr->sh_info * e_shentsize); /* Buffer loaded symbols */ ulong[] sym_buf = new ulong[cur_symtab->sh_size / cur_symtab->sh_entsize]; /* Load section */ byte *shdr_data = ReadStructure(s, cur_shdr->sh_offset, cur_shdr->sh_size); cur_shdr->sh_addr = (ulong)shdr_data; ulong offset = 0; while (offset < cur_shdr->sh_size) { ElfReader.Elf64_Rela *cur_rela = (ElfReader.Elf64_Rela *)(shdr_data + offset); ulong r_offset = rela_sect->sh_addr + cur_rela->r_offset; ulong r_sym = cur_rela->r_info >> 32; ulong r_type = cur_rela->r_info & 0xffffffff; long r_addend = cur_rela->r_addend; ElfReader.Elf64_Sym *rela_sym = (ElfReader.Elf64_Sym *)(cur_symtab->sh_addr + r_sym * cur_symtab->sh_entsize); uint st_bind = (rela_sym->st_info_other_shndx >> 4) & 0xf; ulong S = 0; /* Can use direct relocation via the symbol table if: * - not weak * - is defined */ if ((st_bind == 0 || st_bind == 1) && rela_sym->st_shndx != 0) { /* STB_LOCAL symbols have not been loaded into the symbol table * We need to use the value stored in the symbol table */ uint st_shndx = (rela_sym->st_info_other_shndx >> 16) & 0xffff; S = ((ElfReader.Elf64_Shdr *)(shdrs + e_shentsize * st_shndx))->sh_addr + rela_sym->st_value; } else { /* Get the symbol address from the symbol table if not already loaded */ if (sym_buf[r_sym] == 0) { ElfReader.Elf64_Shdr *link_sect = (ElfReader.Elf64_Shdr *)(shdrs + cur_symtab->sh_link * e_shentsize); string sym_name = new string((sbyte *)(link_sect->sh_addr + rela_sym->st_name)); S = stab.GetAddress(sym_name); if (S == 0) { throw new Exception("undefined reference to " + sym_name); } sym_buf[r_sym] = S; } else { S = sym_buf[r_sym]; } } /* Perform the relocation */ switch (r_type) { case 1: // R_X86_64_64: S + A { ulong c = S; if (r_addend > 0) { c += (ulong)r_addend; } else { c -= (ulong)(-r_addend); } *(ulong *)r_offset = c; } break; case 2: // R_X86_64_PC32: S + A - P { if (S > (ulong)long.MaxValue) { throw new Exception("S too large"); } if (r_offset > (ulong)long.MaxValue) { throw new Exception("P too large"); } long c = (long)S + r_addend - (long)r_offset; if (c < int.MinValue || c > int.MaxValue) { throw new Exception("Relocation truncated to fit"); } *(int *)r_offset = (int)c; } break; case 10: // R_X86_64_32: S + A { if (S > (ulong)long.MaxValue) { throw new Exception("S too large"); } long c = (long)S + r_addend; if (c < 0 || c > uint.MaxValue) { throw new Exception("Relocation truncated to fit"); } *(uint *)r_offset = (uint)c; } break; case 11: // R_X86_64_32S: S + A { if (S > (ulong)long.MaxValue) { throw new Exception("S too large"); } long c = (long)S + r_addend; if (c < int.MinValue || c > int.MaxValue) { throw new Exception("Relocation truncated to fit"); } *(int *)r_offset = (int)c; } break; default: throw new Exception("Unsupported relocation type: " + r_type.ToString()); } offset += cur_shdr->sh_entsize; } } sect_header += e_shentsize; } System.Diagnostics.Debugger.Log(0, null, "ElfFileReader.LoadObject: end fixing relocations"); if (start == 0) { // assume .to file - use entry point in header start = text_section + hdr_epoint; } return(start); }