View of xos/usr/lib/ld-so/resolve.c


XOS | Parent Directory | View | Download

/* Resolution des references symboliques. */
/* Copyright (C) 2008  Emmanuel Varoquaux
 
   This file is part of XOS.
 
   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.
 
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
 
   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
#include "resolve.h"
#include "vars.h"
#include "object_info.h"
 
#include <string.h>
 
/* Cherche un symbole de nom symbol_name dans l'objet object_info.
 * symbol_name doit etre non vide. */
static const Elf32_Sym *lookup_symbol(const char *symbol_name, const struct object_info_struct *object_info)
{
  const char *string_table;
  const Elf32_Sym *symbol_table;
  const Elf32_Word *symbol_hash_table;
  int nbuckets;
  const Elf32_Word *bucket_array;
  const Elf32_Word *chain_array;
  register int idx;
 
  string_table = object_info->dynamic_data.string_table;
  symbol_table = object_info->dynamic_data.symbol_table;
  symbol_hash_table = object_info->dynamic_data.symbol_hash_table;
  nbuckets = symbol_hash_table[0];
  if (nbuckets == 0)
    return NULL;
  bucket_array = symbol_hash_table + 2;
  chain_array = bucket_array + nbuckets;
  idx = bucket_array[elf_hash((const unsigned char *)symbol_name) % nbuckets];
  while (1) {
    if (!strcmp(symbol_name, string_table + symbol_table[idx].st_name))
      return &symbol_table[idx];
    if (chain_array[idx] == STN_UNDEF)
      return NULL;
    idx = chain_array[idx];
  }
}
 
/* Cherche un symbole defini de nom symbol_name dans l'objet object_info.
 * symbol_name doit etre non vide. */
static const Elf32_Sym *search_symbol_definition(const char *symbol_name, struct object_info_struct *object_info)
{
  const Elf32_Sym *symbol;
 
  if (!(symbol = lookup_symbol(symbol_name, object_info)))
    return NULL;
  if (symbol->st_shndx != SHN_UNDEF)
    return symbol;
  if (object_info->type == OI_EXEC && ELF32_ST_TYPE(symbol->st_info) == STT_FUNC && symbol->st_value)
    return symbol;
  return NULL;
}
 
int resolve_symbol(struct object_info_struct *object_info, const Elf32_Sym *symbol, int flags, struct object_info_struct **found_object_info, const Elf32_Sym **found_symbol)
{
  const char *symbol_name;
  struct object_info_struct *object_info_1;
 
  if (!symbol->st_name)
    return 0;
  symbol_name = object_info->dynamic_data.string_table + symbol->st_name;
 
  /* DT_SYMBOLIC : recherche d'abord dans l'objet partage. */
  if (object_info->type != OI_EXEC && object_info->dynamic_data.symbolic)
    if ((*found_symbol = search_symbol_definition(symbol_name, object_info))) {
      *found_object_info = object_info;
      return 1;
    }
 
  /* Recherche d'abord dans l'executable. */
  if (!(flags & RF_NOEXEC))
    if ((*found_symbol = search_symbol_definition(symbol_name, &executable_info))) {
      *found_object_info = &executable_info;
      return 1;
    }
 
  /* Recherche dans les objets partages. */
  for (object_info_1 = shared_object_info_list.first; object_info_1; object_info_1 = object_info_1->next)
    if ((*found_symbol = search_symbol_definition(symbol_name, object_info_1))) {
      *found_object_info = object_info_1;
      return 1;
    }
 
  /* Reference symbolique non trouvee. */
 
  /* Symbole faible ? */
  if (ELF32_ST_BIND(symbol->st_info) == STB_WEAK) {
    *found_symbol = NULL;
    *found_object_info = NULL;
    return 1;
  }
 
  /* Echec de la resolution. */
  return 0;
}