Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /****************************  elf2asm.cpp   *********************************
  2. * Author:        Agner Fog
  3. * Date created:  2007-04-22
  4. * Last modified: 2016-11-06
  5. * Project:       objconv
  6. * Module:        elf2asm.cpp
  7. * Description:
  8. * Module for disassembling ELF
  9. *
  10. * Copyright 2007-2016 GNU General Public License http://www.gnu.org/licenses
  11. *****************************************************************************/
  12. #include "stdafx.h"
  13. // All functions in this module are templated to make two versions: 32 and 64 bits.
  14. // See instantiations at the end of this file.
  15.  
  16.  
  17. // Constructor
  18. template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
  19. CELF2ASM<ELFSTRUCTURES>::CELF2ASM() {
  20. }
  21.  
  22.  
  23. // FindImageBase()
  24. template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
  25. void CELF2ASM<ELFSTRUCTURES>::FindImageBase() {
  26.    // Find image base if executable file
  27.  
  28.    // Check if executable
  29.    switch (this->FileHeader.e_type) {
  30.    case ET_REL: default:
  31.       // Not an executable file
  32.       ExeType = 0;  ImageBase = 0;
  33.       return;
  34.    case ET_DYN: // Shared object
  35.       ExeType = 1;
  36.       break;
  37.    case ET_EXEC: // Executable file
  38.       ExeType = 2;
  39.       break;
  40.    }
  41.  
  42.    // Loop through sections to find the first allocated section
  43.    for (uint32 sc = 0; sc < this->NSections; sc++) {
  44.       if (this->SectionHeaders[sc].sh_type == SHT_PROGBITS    // Must be code or data section
  45.       && (this->SectionHeaders[sc].sh_flags & SHF_ALLOC)      // Must be allocated
  46.       && this->SectionHeaders[sc].sh_offset <= this->SectionHeaders[sc].sh_addr) { // Avoid negative
  47.          // Image base can be calculated from this section
  48.          ImageBase = this->SectionHeaders[sc].sh_addr - this->SectionHeaders[sc].sh_offset;
  49.          // Make sure ImageBase is divisible by page size
  50.          ImageBase = ImageBase & - 0x1000;
  51.          // Stop searching
  52.          return;
  53.       }
  54.    }
  55.    // Failure. Cannot compute image base from any of the sections
  56.    ImageBase = 0;
  57.    return;    
  58. }
  59.  
  60.  
  61. // Convert
  62. template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
  63. void CELF2ASM<ELFSTRUCTURES>::Convert() {
  64.    // Do the conversion
  65.  
  66.    // Find image base and executable type
  67.    FindImageBase();
  68.  
  69.    // Tell disassembler
  70.    Disasm.Init(ExeType, ImageBase);                       // Set image base
  71.  
  72.    // Make Sections list in Disasm
  73.    MakeSectionList();
  74.  
  75.    // Make Symbols list in Disasm
  76.    MakeSymbolList();
  77.  
  78.    // Make relocations for object and executable files
  79.    MakeRelocations();
  80.  
  81.    if (ImageBase) {
  82.       // Executable file
  83.       MakeImportList();                          // Make imported symbols for executable files
  84.       MakeExportList();                          // Make exported symbols for executable files
  85.       MakeListLabels();                          // Put labels on all image directory tables
  86.    }
  87.    Disasm.Go();                                  // Disassemble
  88.    *this << Disasm.OutFile;                      // Take over output file from Disasm
  89. }
  90.  
  91. // MakeSectionList
  92. template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
  93. void CELF2ASM<ELFSTRUCTURES>::MakeSectionList() {
  94.    // Make Sections list and Relocations list in Disasm
  95.  
  96.    // Allocate array for translating oroginal section numbers to new index
  97.    SectionNumberTranslate.SetNum(this->NSections + 1);
  98.    uint32 NewSectionIndex = 0;
  99.  
  100.    for (uint32 sc = 0; sc < this->NSections; sc++) {
  101.       // Get copy of 32-bit header or converted 64-bit header
  102.       TELF_SectionHeader sheader = this->SectionHeaders[sc];
  103.       //int entrysize = (uint32)(sheader.sh_entsize);
  104.       uint32 namei = sheader.sh_name;
  105.       if (namei >= this->SecStringTableLen) {err.submit(2112); break;}
  106.  
  107. //      if (sheader.sh_type == SHT_PROGBITS || sheader.sh_type == SHT_NOBITS) {
  108. //         // This is a code, data or bss section
  109.  
  110.       if (sheader.sh_flags & SHF_ALLOC) {
  111.          // This is an allocated section
  112.  
  113.          // Give it a new index
  114.          SectionNumberTranslate[sc] = ++NewSectionIndex;
  115.  
  116.          // Get section parameters
  117.          uint8 * Buffer = (uint8*)(this->Buf()) + (uint32)sheader.sh_offset;
  118.          uint32  InitSize = (sheader.sh_type == SHT_NOBITS) ? 0 : (uint32)sheader.sh_size;
  119.          uint32  TotalSize = (uint32)sheader.sh_size;
  120.          uint32  SectionAddress = (uint32)sheader.sh_addr - (uint32)ImageBase;
  121.          uint32  Align = FloorLog2((uint32)sheader.sh_addralign);
  122.          const char * Name = this->SecStringTableLen ? this->SecStringTable + namei : "???";
  123.  
  124.          // Detect segment type
  125.          uint32  Type = 0;
  126.          if (sheader.sh_flags & SHF_ALLOC) {
  127.             // Allocate
  128.             if (sheader.sh_type == SHT_NOBITS) {
  129.                // Uninitialized data
  130.                Type = 3;
  131.             }
  132.             else if (sheader.sh_flags & SHF_EXECINSTR) {
  133.                // Executable
  134.                Type = 1;
  135.             }
  136.             else if (!(sheader.sh_flags & SHF_WRITE)) {
  137.                // Not writeable
  138.                Type = 4;
  139.             }
  140.             else {
  141.                // Initialized writeable data
  142.                Type = 2;
  143.             }
  144.          }
  145.  
  146.          // Save section record
  147.          Disasm.AddSection(Buffer, InitSize, TotalSize, SectionAddress, Type, Align, this->WordSize, Name);
  148.       }
  149.    }
  150. }
  151.  
  152. // MakeSymbolList
  153. template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
  154. void CELF2ASM<ELFSTRUCTURES>::MakeSymbolList() {
  155.    // Make Symbols list in Disasm
  156.  
  157.    // Allocate array for translate symbol indices for multiple symbol tables in
  158.    // source file to a single symbol table in disassembler
  159.    SymbolTableOffset.SetNum(this->NSections + 1);
  160.    NumSymbols = 0;
  161.  
  162.    for (uint32 sc = 0; sc < this->NSections; sc++) {
  163.       // Get copy of 32-bit header or converted 64-bit header
  164.       TELF_SectionHeader sheader = this->SectionHeaders[sc];
  165.       int entrysize = (uint32)(sheader.sh_entsize);
  166.  
  167.       if (sheader.sh_type==SHT_SYMTAB || sheader.sh_type==SHT_DYNSYM) {
  168.          // This is a symbol table
  169.  
  170.          // Offset for symbols in this symbol table = number of preceding symbols from other symbol tables
  171.          SymbolTableOffset[sc] = NumSymbols;
  172.  
  173.          // Find associated string table
  174.          if (sheader.sh_link >= this->NSections) {err.submit(2035); sheader.sh_link = 0;}
  175.          int8 * strtab = this->Buf() + uint32(this->SectionHeaders[sheader.sh_link].sh_offset);
  176.  
  177.          // Find symbol table
  178.          uint32 symtabsize = (uint32)(sheader.sh_size);
  179.          int8 * symtab = this->Buf() + uint32(sheader.sh_offset);
  180.          int8 * symtabend = symtab + symtabsize;
  181.          if (entrysize < (int)sizeof(TELF_Symbol)) {err.submit(2033); entrysize = (int)sizeof(TELF_Symbol);}
  182.  
  183.          // Loop through symbol table
  184.          uint32 symi1;                           // Symbol number in this table
  185.          uint32 symi2;                           // Symbol number in joined table
  186.          symtab += entrysize;                    // Skip symbol number 0
  187.          for (symi1 = 1; symtab < symtabend; symtab += entrysize, symi1++) {
  188.  
  189.             // Symbol number in joined table = symi1 + number of symbols in preceding tables
  190.             symi2 = SymbolTableOffset[sc] + symi1;
  191.            
  192.             // Copy 32 bit symbol table entry or convert 64 bit entry
  193.             TELF_Symbol sym = *(TELF_Symbol*)symtab;
  194.  
  195.             // Parameters
  196.             uint32 Offset = uint32(sym.st_value);
  197.             uint32 Size = (uint32)sym.st_size;
  198.  
  199.             // Get section
  200.             int32 Section = int16(sym.st_shndx);
  201.             if (Section >= (int32)(this->NSections)) {
  202.                // Error. wrong section
  203.                Section = 0;
  204.             }
  205.             if (Section > 0) {
  206.                // Translate to new section index
  207.                Section = SectionNumberTranslate[Section];
  208.             }
  209.             else if ((int16)Section < 0) {
  210.                // Special section values
  211.                if ((int16)Section == SHN_ABS) {
  212.                   // Absolute symbol
  213.                   Section = ASM_SEGMENT_ABSOLUTE;
  214.                }
  215.                else {
  216.                   // Other special values
  217.                   Section = ASM_SEGMENT_ERROR;
  218.                }
  219.             }
  220.  
  221.             // Get name
  222.             const char * Name = 0;
  223.             if (*(strtab + sym.st_name)) {
  224.                Name = strtab + sym.st_name;
  225.             }
  226.            
  227.             // Get import .so name
  228.             const char * DLLName = 0;
  229.             if (sheader.sh_type==SHT_DYNSYM && sym.st_value == 0
  230.             && sym.st_shndx == 0 && sym.st_size > 0) {
  231.                // I don't know how to find out which .so the symbol is imported from
  232.                // It must be something in the .dynamic section.
  233.                DLLName = "?.so";
  234.             }
  235.  
  236.             // Get scope
  237.             uint32 Scope = 0;
  238.             switch (sym.st_bind) {
  239.             case STB_LOCAL:
  240.                Scope = 2;
  241.                break;
  242.             case STB_WEAK:
  243.                Scope = 8;
  244.                if (Section > 0) break;
  245.                // Section == 0: continue as global
  246.             case STB_GLOBAL:
  247.                // Public or external
  248.                Scope = (sym.st_shndx > 0) ? 4 : 0x20;
  249.                break;
  250.             }
  251.             // Get type
  252.             uint32 Type = 0;
  253.  
  254.             if (sym.st_type == STT_FUNC) {
  255.                // Function
  256.                Type = 0x83;
  257.             }
  258.             else if (sym.st_type == STT_GNU_IFUNC) {
  259.                // Gnu indirect function
  260.                Type = 0x40000083;
  261.             }
  262.             else if (sym.st_type == STT_OBJECT) {
  263.                // Probably a data object
  264.                switch (Size) {
  265.                case 1:
  266.                   Type = 1;
  267.                   break;
  268.                case 2:
  269.                   Type = 2;
  270.                   break;
  271.                case 4:
  272.                   Type = 3;
  273.                   break;
  274.                case 8:
  275.                   Type = 4;
  276.                   break;
  277.                default:
  278.                   Type = 1;
  279.                   break;
  280.                }
  281.             }
  282.             else if (sym.st_type == STT_COMMON) {
  283.                // Communal?
  284.                Type = 0;
  285.                Scope = 0x10;
  286.             }
  287.             else if (sym.st_type == STT_SECTION) {
  288.                // This is a section
  289.                Type = 0x80000082;
  290.                Scope = 0;
  291.             }
  292.             else if (sym.st_type == STT_NOTYPE) {
  293.                Type = 0;
  294.             }
  295.             else if (sym.st_type == STT_FILE) {
  296.                // file name. ignore
  297.                continue;
  298.             }            
  299.             else {
  300.                // unknown type. warning
  301.                err.submit(1062, Name);
  302.                Type = 0;
  303.                //continue;
  304.             }
  305.  
  306.             if (Scope != 0x20) {
  307.                // Not external
  308.                // Check if offset is absolute or section relative
  309.                if (ExeType && Offset >= (uint32)ImageBase) {
  310.                   // Offset is absolute address
  311.                   if (Section >= 0
  312.                      && (uint32)Section < this->NSections
  313.                      && Offset >= (uint32)this->SectionHeaders[Section].sh_addr
  314.                      && Offset - (uint32)this->SectionHeaders[Section].sh_addr < (uint32)(this->SectionHeaders[Section].sh_size)) {
  315.                         // Change to section relative offset
  316.                         Offset -= (uint32)(this->SectionHeaders[Section].sh_addr);
  317.                      }
  318.                   else {
  319.                      // Address is outside specified section or otherwise inconsistent.
  320.                      // Let Disasm try to find the address
  321.                      Section = ASM_SEGMENT_IMGREL;
  322.                      Offset -= (uint32)ImageBase;
  323.                   }
  324.                }
  325.             }
  326.  
  327.             // Store new symbol record
  328.             Disasm.AddSymbol(Section, Offset, Size, Type, Scope, symi2, Name, DLLName);
  329.  
  330.             // Count symbols
  331.             NumSymbols++;
  332.          }
  333.       }
  334.    }
  335. }
  336.  
  337. // MakeRelocations
  338. template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
  339. void CELF2ASM<ELFSTRUCTURES>::MakeRelocations() {
  340.    // Make relocations for object and executable files
  341.  
  342.    int32 Section;                                // Source section new index
  343.  
  344.    // Loop through sections
  345.    for (uint32 sc = 0; sc < this->NSections; sc++) {
  346.       // Get copy of 32-bit header or converted 64-bit header
  347.       TELF_SectionHeader sheader = this->SectionHeaders[sc];
  348.       int entrysize = (uint32)(sheader.sh_entsize);
  349.  
  350.       if (sheader.sh_type == SHT_REL || sheader.sh_type == SHT_RELA) {
  351.          // Relocations section
  352.          int8 * reltab = this->Buf() + uint32(sheader.sh_offset);
  353.          int8 * reltabend = reltab + uint32(sheader.sh_size);
  354.          int expectedentrysize = sheader.sh_type == SHT_RELA ?
  355.             sizeof(TELF_Relocation) :              // Elf32_Rela, Elf64_Rela
  356.             sizeof(TELF_Relocation) - this->WordSize/8;  // Elf32_Rel,  Elf64_Rel
  357.          if (entrysize < expectedentrysize) {err.submit(2033); entrysize = expectedentrysize;}
  358.  
  359.          // Loop through entries
  360.          for (; reltab < reltabend; reltab += entrysize) {
  361.             // Copy relocation table entry with or without addend
  362.             TELF_Relocation rel;  rel.r_addend = 0;
  363.             memcpy(&rel, reltab, entrysize);
  364.  
  365.             // Get section-relative or absolute address
  366.             uint32  Offset = (uint32)rel.r_offset;
  367.  
  368.             // Get addend, if any
  369.             int32   Addend = (uint32)rel.r_addend;
  370.  
  371.             // Find target symbol
  372.             uint32  TargetIndex = rel.r_sym;
  373.             if (sheader.sh_link < this->NSections) {
  374.                // sh_link indicates which symbol table r_sym refers to
  375.                TargetIndex += SymbolTableOffset[sheader.sh_link];
  376.             }
  377.  
  378.             // Find section
  379.             if (sheader.sh_info < this->NSections) {            
  380.                Section = SectionNumberTranslate[sheader.sh_info];
  381.             }
  382.             else {
  383.                // Not found. Try to let disasm find by absolute address
  384.                Section = ASM_SEGMENT_IMGREL;
  385.                if (Offset < (uint32)ImageBase) Offset += (uint32)ImageBase;
  386.             }
  387.  
  388.             // Get relocation type and size
  389.             uint32  Type = 0;
  390.             uint32  Size = 0;
  391.             if (this->WordSize == 32) {
  392.                switch (rel.r_type) {
  393.                case R_386_RELATIVE: // Adjust by program base
  394.                   Type = 0x21;  Size = 4;
  395.                   break;
  396.                case R_386_JMP_SLOT: // Create PLT entry
  397.                   Type = 0x41;  Size = 4;
  398.                   break;
  399.                case R_386_PLT32: // Self-relative to PLT
  400.                   Type = 0x2002;  Size = 4;
  401.                   break;
  402.                case R_386_32:
  403.                   // Direct 32 bit
  404.                   Type = 1;  Size = 4;
  405.                   break;
  406.                case R_386_PC32:
  407.                   // Self-relative 32 bit
  408.                   Type = 2;  Size = 4;
  409.                   break;
  410.                case R_386_GOTPC:
  411.                   // Self-relative offset to GOT
  412.                   Type = 0x1002;  Size = 4;
  413.                   break;
  414.                case R_386_IRELATIVE:
  415.                   // Reference to Gnu indirect function
  416.                   Type = 0x81;  Size = 4;
  417.                   break;
  418.                case R_386_GLOB_DAT:
  419.                case R_386_GOT32:
  420.                case R_386_GOTOFF:
  421.                   // Create GOT entry
  422.                   Type = 0x1001;  Size = 4;
  423.                   break;
  424.                }
  425.             }
  426.             else {
  427.                // 64 bit
  428.                switch (rel.r_type) {
  429.                case R_X86_64_RELATIVE:  // Adjust by program base
  430.                   Type = 0x21;  Size = 8;
  431.                   break;
  432.                case R_X86_64_JUMP_SLOT: // Create PLT entry
  433.                   Type = 0x41;  Size = 8;
  434.                   break;
  435.                case R_X86_64_64:
  436.                   // Direct 64 bit
  437.                   Type = 1;  Size = 8;
  438.                   break;
  439.                case R_X86_64_PC32:
  440.                   // Self relative 32 bit signed
  441.                   Type = 2;  Size = 4;
  442.                   break;
  443.                case R_X86_64_32: case R_X86_64_32S:
  444.                   // Direct 32 bit zero extended or sign extend
  445.                   Type = 1;  Size = 4;
  446.                   break;
  447.                case R_X86_64_16:
  448.                   // Direct 16 bit zero extended
  449.                   Type = 1;  Size = 2;
  450.                   break;
  451.                case R_X86_64_PC16:
  452.                   // 16 bit sign extended pc relative
  453.                   Type = 2;  Size = 2;
  454.                   break;
  455.                case R_X86_64_8:
  456.                   // Direct 8 bit sign extended
  457.                   Type = 1;  Size = 1;
  458.                   break;
  459.                case R_X86_64_PC8:
  460.                   // 8 bit sign extended pc relative
  461.                   Type = 2;  Size = 1;
  462.                   break;
  463.                case R_X86_64_GOTPCREL:
  464.                   // Self relative 32 bit signed offset to GOT entry
  465.                   Type = 0x1002;  Size = 4;
  466.                   break;
  467.                case R_X86_64_IRELATIVE:
  468.                   // Reference to Gnu indirect function
  469.                   Type = 0x81;  Size = 4;
  470.                   break;
  471.                case R_X86_64_PLT32:  // Self-relative to PLT
  472.                   Type = 0x2002;  Size = 4;
  473.                   break;
  474.                case R_X86_64_GLOB_DAT:  // Create GOT entry
  475.                case R_X86_64_GOT32:
  476.                   Type = 0x1001;  Size = 4;
  477.                   break;
  478.                }
  479.             }
  480.  
  481.             // Check if offset is absolute or section relative
  482.             if (ImageBase && Offset > (uint32)ImageBase) {
  483.                // Offset is absolute address
  484.                if (Section > 0 && (uint32)Section < this->NSections
  485.                && Offset >= (uint32)(this->SectionHeaders[Section].sh_addr)
  486.                && Offset - (uint32)(this->SectionHeaders[Section].sh_addr) < (uint32)(this->SectionHeaders[Section].sh_size)) {
  487.                   // Change to section relative offset
  488.                   Offset -= (uint32)(this->SectionHeaders[Section].sh_addr);
  489.                }
  490.                else {
  491.                   // Inconsistent. Let Disasm try to find the address
  492.                   Section = ASM_SEGMENT_IMGREL;
  493.                   Offset -= (uint32)ImageBase;
  494.                }
  495.             }
  496.  
  497.             // Save relocation record
  498.             Disasm.AddRelocation(Section, Offset, Addend, Type, Size, TargetIndex);
  499.          }
  500.       }
  501.    }
  502. }
  503.  
  504.  
  505. // MakeImportList
  506. template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
  507. void CELF2ASM<ELFSTRUCTURES>::MakeImportList() {
  508.    // Make imported symbols for executable files
  509. }
  510.  
  511. // MakeExportList
  512. template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
  513. void CELF2ASM<ELFSTRUCTURES>::MakeExportList() {
  514.    // Make exported symbols for executable files
  515. }
  516.  
  517. // MakeListLabels
  518. template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
  519. void CELF2ASM<ELFSTRUCTURES>::MakeListLabels() {
  520.    // Attach names to all image directories
  521. }
  522.  
  523.  
  524. // Make template instances for 32 and 64 bits
  525. template class CELF2ASM<ELF32STRUCTURES>;
  526. template class CELF2ASM<ELF64STRUCTURES>;
  527.