Exemplo n.º 1
0
Arquivo: pe.c Projeto: HarryR/sanos
int pe_load_res_file(TCCState *s1, int fd) {
  struct pe_rsrc_header hdr;
  Section *rsrc_section;
  int i, ret = -1;
  BYTE *ptr;

  lseek(fd, 0, SEEK_SET);
  if (!read_n(fd, &hdr, sizeof hdr)) goto quit;
  if (!pe_test_res_file(&hdr, sizeof hdr)) goto quit;

  rsrc_section = new_section(s1, ".rsrc", SHT_PROGBITS, SHF_ALLOC);
  ptr = section_ptr_add(rsrc_section, hdr.sectionhdr.SizeOfRawData);
  lseek(fd, hdr.sectionhdr.PointerToRawData, SEEK_SET);
  if (!read_n(fd, ptr, hdr.sectionhdr.SizeOfRawData)) goto quit;

  lseek(fd, hdr.sectionhdr.PointerToRelocations, SEEK_SET);
  for (i = 0; i < hdr.sectionhdr.NumberOfRelocations; ++i) {
    struct pe_rsrc_reloc rel;
    if (!read_n(fd, &rel, sizeof rel)) goto quit;
    if (rel.type != 7) goto quit; // DIR32NB
    put_elf_reloc(symtab_section, rsrc_section, rel.offset, R_386_RELATIVE, 0);
  }
  ret = 0;
quit:
  if (ret) error_noabort("unrecognized resource file format");
  return ret;
}
Exemplo n.º 2
0
/* 'is_jmp' is '1' if it is a jump */
static void gcall_or_jmp(int is_jmp)
{
    int r;
    if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
        /* constant case */
        if (vtop->r & VT_SYM) {
            /* relocation case */
            greloc(cur_text_section, vtop->sym, 
                   ind + 1, R_386_PC32);
        } else {
            /* put an empty PC32 relocation */
            put_elf_reloc(symtab_section, cur_text_section, 
                          ind + 1, R_386_PC32, 0);
        }
        oad(0xe8 + is_jmp, vtop->c.ul - 4); /* call/jmp im */
    } else {
        /* otherwise, indirect call */
        r = gv(RC_INT);
        o(0xff); /* call/jmp *r */
        o(0xd0 + r + (is_jmp << 4));
    }
}
Exemplo n.º 3
0
Arquivo: pe.c Projeto: HarryR/sanos
static int pe_check_symbols(struct pe_info *pe) {
  Elf32_Sym *sym;
  int sym_index, sym_end;
  int ret = 0;

  pe_align_section(text_section, 8);

  sym_end = symtab_section->data_offset / sizeof(Elf32_Sym);
  for (sym_index = 1; sym_index < sym_end; ++sym_index) {
    sym = (Elf32_Sym *) symtab_section->data + sym_index;
    if (sym->st_shndx == SHN_UNDEF) {
      const char *name = symtab_section->link->data + sym->st_name;
      unsigned type = ELF32_ST_TYPE(sym->st_info);
      int imp_sym = pe_find_import(pe->s1, name);
      struct import_symbol *is;

      if (imp_sym == 0) goto not_found;
      is = pe_add_import(pe, imp_sym);
      if (!is) goto not_found;

      if (type == STT_FUNC) {
        unsigned long offset = is->thk_offset;
        if (offset) {
          // Got aliased symbol, like stricmp and _stricmp
        } else {
          char buffer[100];

          offset = text_section->data_offset;
          // Add the 'jmp IAT[x]' instruction
          *(WORD *) section_ptr_add(text_section, 8) = 0x25FF;

          // Add a helper symbol, will be patched later in pe_build_imports
          sprintf(buffer, "IAT.%s", name);
          is->iat_index = put_elf_sym(symtab_section, 0, sizeof(DWORD),
                                      ELF32_ST_INFO(STB_GLOBAL, STT_OBJECT),
                                      0, SHN_UNDEF, buffer);
          put_elf_reloc(symtab_section, text_section, offset + 2, R_386_32, is->iat_index);
          is->thk_offset = offset;
        }

        // tcc_realloc might have altered sym's address
        sym = (Elf32_Sym *) symtab_section->data + sym_index;

        // Patch the original symbol
        sym->st_value = offset;
        sym->st_shndx = text_section->sh_num;
        sym->st_other &= ~1; // Do not export
        continue;
      }

      if (type == STT_OBJECT) { 
        if (is->iat_index == 0) {
          // Original symbol will be patched later in pe_build_imports
          is->iat_index = sym_index;
          continue;
        }
      }

    not_found:
      error_noabort("undefined symbol '%s'", name);
      ret = 1;
    } else if (pe->s1->rdynamic && ELF32_ST_BIND(sym->st_info) != STB_LOCAL) {
      // If -rdynamic option, then export all non local symbols
      sym->st_other |= 1;
    }
  }
  return ret;
}
Exemplo n.º 4
0
Arquivo: pe.c Projeto: HarryR/sanos
static void pe_build_exports(struct pe_info *pe) {
  Elf32_Sym *sym;
  int sym_index, sym_end;
  DWORD rva_base, func_o, name_o, ord_o, str_o;
  struct pe_export_header *hdr;
  int sym_count, n, ord, *sorted, *sp;

  FILE *op;
  char buf[260];
  const char *dllname;
  const char *name;

  rva_base = pe->thunk->sh_addr - pe->imagebase;
  sym_count = 0;
  n = 1;
  sorted = NULL;
  op = NULL;

  sym_end = symtab_section->data_offset / sizeof(Elf32_Sym);
  for (sym_index = 1; sym_index < sym_end; ++sym_index) {
    sym = (Elf32_Sym *) symtab_section->data + sym_index;
    name = symtab_section->link->data + sym->st_name;
    // Only export symbols from actually written sections
    if ((sym->st_other & 1) && pe->s1->sections[sym->st_shndx]->sh_addr) {
      dynarray_add((void ***) &sorted, &sym_count, (void *) n);
      dynarray_add((void ***) &sorted, &sym_count, (void *) name);
    }
    ++n;
  }

  if (sym_count == 0) return;
  sym_count /= 2;

  qsort(sorted, sym_count, 2 * sizeof(sorted[0]), sym_cmp);
  pe_align_section(pe->thunk, 16);
  dllname = tcc_basename(pe->filename);

  pe->exp_offs = pe->thunk->data_offset;
  func_o = pe->exp_offs + sizeof(struct pe_export_header);
  name_o = func_o + sym_count * sizeof(DWORD);
  ord_o = name_o + sym_count * sizeof(DWORD);
  str_o = ord_o + sym_count * sizeof(WORD);

  hdr = section_ptr_add(pe->thunk, str_o - pe->exp_offs);
  hdr->Characteristics = 0;
  hdr->Base = 1;
  hdr->NumberOfFunctions = sym_count;
  hdr->NumberOfNames = sym_count;
  hdr->AddressOfFunctions = func_o + rva_base;
  hdr->AddressOfNames = name_o + rva_base;
  hdr->AddressOfNameOrdinals = ord_o + rva_base;
  hdr->Name = str_o + rva_base;
  put_elf_str(pe->thunk, dllname);

  if (pe->def != NULL) {
    // Write exports to .def file
    op = fopen(pe->def, "w");
    if (op == NULL) {
      error_noabort("could not create '%s': %s", pe->def, strerror(errno));
    } else {
      fprintf(op, "LIBRARY %s\n\nEXPORTS\n", dllname);
      if (verbose) {
        printf("<- %s (%d symbols)\n", buf, sym_count);
      }
    }
  }

  for (sp = sorted, ord = 0; ord < sym_count; ++ord, sp += 2) {
    sym_index = sp[0]; 
    name = (const char *) sp[1];

    // Insert actual address later in pe_relocate_rva
    put_elf_reloc(symtab_section, pe->thunk, func_o, R_386_RELATIVE, sym_index);
    *(DWORD *)(pe->thunk->data + name_o) = pe->thunk->data_offset + rva_base;
    *(WORD *)(pe->thunk->data + ord_o) = ord;
    put_elf_str(pe->thunk, name);
    func_o += sizeof(DWORD);
    name_o += sizeof(DWORD);
    ord_o += sizeof(WORD);

    if (op) fprintf(op, "%s@%d\n", name, ord);
  }
  pe->exp_size = pe->thunk->data_offset - pe->exp_offs;
  tcc_free(sorted);
  if (op) fclose(op);
}
Exemplo n.º 5
0
void gcode(void) {
  int i, n, t, r, stacksize, addr, pc, disp, rel, errs, more, func_start;
  Branch *b, *bn;

  // Generate function prolog
  func_start = cur_text_section->data_offset;
  if (!func_naked) {
    // Align local size to word
    stacksize = (-loc + 3) & -4;

    if (stacksize >= 4096) {
      // Generate stack guard since parameters can cross page boundary
      Sym *sym = external_global_sym(TOK___chkstk, &func_old_type, 0);
      gen(0xb8); // mov stacksize, %eax
      genword(stacksize);
      gen(0xe8);  // call __chkstk, (does the stackframe too)
      put_reloc(cur_text_section, sym, cur_text_section->data_offset, R_386_PC32);
      genword(-4);
    } else {
      if (do_debug || loc || !func_noargs) {
        gen(0x55); // push %ebp
        gen(0x89); // mov %esp, %ebp
        gen(0xe5);
      }
      if (stacksize > 0) {
        if (stacksize == (char) stacksize) {
          gen(0x83);  // sub esp, stacksize
          gen(0xec);
          gen(stacksize);
        } else {
          gen(0x81);  // sub esp, stacksize
          gen(0xec);
          genword(stacksize);
        }
      }
    }
    
    // Save callee-saved registers used by function.
    for (r = 0; r < NB_REGS; ++r) {
      if ((reg_classes[r] & RC_SAVE) && (regs_used & (1 << r))) {
        gen(0x50 + r); // push r
      }
    }
  }

  // Optimize jumps
  more = 1;
  while (more) {
    more = 0;

    for (i = 0; i < br; ++i) {
      b = branch + i;
      if (b->type == CodeLabel) b->target = 0;
      if (b->type != CodeJump) continue;

      t = skip_nops(b->target, 1);
      if (branch[t].type == CodeJump && !branch[t].param && b->target != branch[t].target) {
        // Eliminate jump to jump
        b->target = branch[t].target;
        more = 1;
        continue;
      }

      // Find next non-nop
      n = i + 1;
      while (branch[n].type == CodeNop || branch[n].type == CodeLine) n++;
      bn = branch + n;
      if (b->ind != bn->ind) continue;

      if (!b->param && bn->type == CodeJump) {
        // Eliminate dead jump instruction
        bn->type = CodeNop;
        more = 1;
        continue;
      }

      if (b->target > i && b->target <= n) {
        // Eliminate jump to next instruction
        b->type = CodeNop;
        more = 1;
        continue;
      }
      
      t = skip_nops(n + 1, 0);
      if (bn->type == CodeJump && !bn->param && b->target == t && bn->ind == branch[t].ind) {
        // Optimize inverted jump
        if (b->param) b->param ^= 1;
        b->target = bn->target;
        bn->type = CodeNop;
        more = 1;
        continue;
      }
    }

    // Eliminate unused labels
    for (i = 0; i < br; ++i) {
      b = branch + i;
      if (b->type == CodeJump) branch[b->target].target++;
    }
    for (i = 0; i < br; ++i) {
      b = branch + i;
      if (b->type == CodeLabel && !b->target && !b->sym) {
        // Remove label with no references
        b->type = CodeNop;
        more = 1;
      }
    }
  }

  // Assign addresses to branch points, assuming only long jumps
  addr = cur_text_section->data_offset;
  pc = 0;
  for (i = 0; i < br; ++i) {
    b = branch + i;
    addr += b->ind - pc;
    b->addr = addr;
    switch (b->type) {
      case CodeJump:
        addr += 5;
        if (b->param != 0) addr++;
        break;
        
      case CodeAlign:
        // Use convervative estimate for short/long jump estimation
        addr += b->param - 1;
        break;
    }
    pc = b->ind;
  }
  
  // Find jumps which can be encoded as short jumps
  for (i = 0; i < br; ++i) {
    b = branch + i;
    if (b->type == CodeJump) {
      disp = branch[b->target].addr - b->addr - 2;
      if (b->param) disp--;
      if (disp == (char) disp) b->type = CodeShortJump;
    }
  }

  // Assign final addresses to branch points
  addr = cur_text_section->data_offset;
  pc = 0;
  for (i = 0; i < br; ++i) {
    b = branch + i;
    addr += b->ind - pc;
    b->addr = addr;
    switch (b->type) {
      case CodeJump:
        addr += 5;
        if (b->param) addr++;
        break;

      case CodeShortJump:
        addr += 2;
        break;
      
      case CodeAlign:
        addr = (addr + b->param - 1) & -b->param;
        break;
    }
    pc = b->ind;
  }

  // Generate code blocks
  pc = 0;
  errs = 0;
  for (i = 0; i < br; ++i) {
    b = branch + i;
    
    // Output code block before branch point
    if (b->ind != pc) {
      genblk(code + pc, b->ind - pc);
      pc = b->ind;
    }

    switch (b->type) {
      case CodeLabel:
        // Export label if symbol defined
        if (b->sym) {
          put_extern_sym_ex(b->sym, cur_text_section, b->addr, 0, 0);
          sym_free(b->sym);
        }
        break;

      case CodeJump:
        // Generate long jump instruction
        if (branch[b->target].type != CodeLabel) {
          printf("internal error: jump %d to non-label %d\n", i, b->target);
          errs++;
        }
        if (b->param > 0xff) error("invalid displacement");
        if (b->param == 0) {
          gen(0xe9);
          genword(branch[b->target].addr - (b->addr + 5));
        } else {
          gen(0x0f);
          gen(b->param - 0x10);
          genword(branch[b->target].addr - (b->addr + 6));
        }
        break;

      case CodeShortJump:
        // Generate short jump instruction
        if (branch[b->target].type != CodeLabel) {
          printf("internal error: jump %d to non-label %d\n", i, b->target);
          errs++;
        }
        if (b->param == 0) {
          gen(0xeb);
        } else {
          gen(b->param - 0x20);
        }
        gen(branch[b->target].addr - (b->addr + 2));
        break;

      case CodeReloc:
        if (b->param) {
          rel = R_386_PC32;
        } else {
          rel = R_386_32;
        }
        put_elf_reloc(symtab_section, cur_text_section, b->addr, rel, b->target);
        break;
        
      case CodeAlign:
        i = addr;
        while (i & (b->param - 1)) {
          gen(b->target);
          i++;
        }
        break;

      case CodeLine:
        put_stabn(N_SLINE, 0, b->target, b->addr - func_start);
        break;
    }
  }

  // Generate function epilog
  if (!func_naked) {
    // Restore callee-saved registers used by function.
    for (r = NB_REGS; r >= 0; --r) {
      if ((reg_classes[r] & RC_SAVE) && (regs_used & (1 << r))) {
        gen(0x58 + r); // pop r
      }
    }

    if (do_debug || loc || !func_noargs) gen(0xc9); // leave

    // Generate return
    if (func_ret_sub == 0) {
      gen(0xc3); // ret
    } else {
      gen(0xc2); // ret n
      gen(func_ret_sub);
      gen(func_ret_sub >> 8);
    }
  }

#ifdef DEBUG_BRANCH
  printf("\nbranch table for %s\n", func_name);
  printf(" #   t targ parm    ind      addr\n");
  printf("---- - ---- ----- -------- --------\n");
  for (i = 0; i < br; ++i) {
    b = branch + i;
    printf("%04d %c %04d %04x %08x %08x", i, "SLJjRANlE"[b->type], b->target, b->param, b->ind, b->addr);
    if (branch[i].sym) {
      printf(" sym=%s", get_tok_str(b->sym->v, NULL));
    }
    printf("\n");
  }
  printf("\n");
#endif

  if (errs) error("internal error: code generation");
}
Exemplo n.º 6
0
ST_FN void pe_build_exports(struct pe_info *pe)
{
    Elf32_Sym *sym;
    int sym_index, sym_end;
    DWORD rva_base, func_o, name_o, ord_o, str_o;
    struct pe_export_header *hdr;
    int sym_count, n, ord, *sorted, *sp;

    FILE *op;
    char buf[MAX_PATH];
    const char *dllname;
    const char *name;

    rva_base = pe->thunk->sh_addr - pe->imagebase;
    sym_count = 0, n = 1, sorted = NULL, op = NULL;

    sym_end = symtab_section->data_offset / sizeof(Elf32_Sym);
    for (sym_index = 1; sym_index < sym_end; ++sym_index) {
        sym = (Elf32_Sym*)symtab_section->data + sym_index;
        name = symtab_section->link->data + sym->st_name;
        if ((sym->st_other & 1)
            /* export only symbols from actually written sections */
            && pe->s1->sections[sym->st_shndx]->sh_addr) {
            dynarray_add((void***)&sorted, &sym_count, (void*)n);
            dynarray_add((void***)&sorted, &sym_count, (void*)name);
        }
        ++n;
#if 0
        if (sym->st_other & 1)
            printf("export: %s\n", name);
        if (sym->st_other & 2)
            printf("stdcall: %s\n", name);
#endif
    }

    if (0 == sym_count)
        return;
    sym_count /= 2;

    qsort (sorted, sym_count, 2 * sizeof sorted[0], sym_cmp);
    pe_align_section(pe->thunk, 16);
    dllname = tcc_basename(pe->filename);

    pe->exp_offs = pe->thunk->data_offset;
    func_o = pe->exp_offs + sizeof(struct pe_export_header);
    name_o = func_o + sym_count * sizeof (DWORD);
    ord_o = name_o + sym_count * sizeof (DWORD);
    str_o = ord_o + sym_count * sizeof(WORD);

    hdr = section_ptr_add(pe->thunk, str_o - pe->exp_offs);
    hdr->Characteristics        = 0;
    hdr->Base                   = 1;
    hdr->NumberOfFunctions      = sym_count;
    hdr->NumberOfNames          = sym_count;
    hdr->AddressOfFunctions     = func_o + rva_base;
    hdr->AddressOfNames         = name_o + rva_base;
    hdr->AddressOfNameOrdinals  = ord_o + rva_base;
    hdr->Name                   = str_o + rva_base;
    put_elf_str(pe->thunk, dllname);

#if 1
    /* automatically write exports to <output-filename>.def */
    strcpy(buf, pe->filename);
    strcpy(tcc_fileextension(buf), ".def");
    op = fopen(buf, "w");
    if (NULL == op) {
        error_noabort("could not create '%s': %s", buf, strerror(errno));
    } else {
        fprintf(op, "LIBRARY %s\n\nEXPORTS\n", dllname);
        if (pe->s1->verbose)
            printf("<- %s (%d symbols)\n", buf, sym_count);
    }
#endif

    for (sp = sorted, ord = 0; ord < sym_count; ++ord, sp += 2)
    {
        sym_index = sp[0], name = (const char *)sp[1];
        /* insert actual address later in pe_relocate_rva */
        put_elf_reloc(symtab_section, pe->thunk,
            func_o, R_386_RELATIVE, sym_index);
        *(DWORD*)(pe->thunk->data + name_o)
            = pe->thunk->data_offset + rva_base;
        *(WORD*)(pe->thunk->data + ord_o)
            = ord;
        put_elf_str(pe->thunk, name);
        func_o += sizeof (DWORD);
        name_o += sizeof (DWORD);
        ord_o += sizeof (WORD);

        if (op)
            fprintf(op, "%s\n", name);
    }
    pe->exp_size = pe->thunk->data_offset - pe->exp_offs;
    tcc_free(sorted);
}