Blame backends/ppc_symbol.c

Packit 032894
/* PPC specific symbolic name handling.
Packit 032894
   Copyright (C) 2004, 2005, 2007, 2014, 2015 Red Hat, Inc.
Packit 032894
   This file is part of elfutils.
Packit 032894
   Written by Ulrich Drepper <drepper@redhat.com>, 2004.
Packit 032894
Packit 032894
   This file is free software; you can redistribute it and/or modify
Packit 032894
   it under the terms of either
Packit 032894
Packit 032894
     * the GNU Lesser General Public License as published by the Free
Packit 032894
       Software Foundation; either version 3 of the License, or (at
Packit 032894
       your option) any later version
Packit 032894
Packit 032894
   or
Packit 032894
Packit 032894
     * the GNU General Public License as published by the Free
Packit 032894
       Software Foundation; either version 2 of the License, or (at
Packit 032894
       your option) any later version
Packit 032894
Packit 032894
   or both in parallel, as here.
Packit 032894
Packit 032894
   elfutils is distributed in the hope that it will be useful, but
Packit 032894
   WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 032894
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 032894
   General Public License for more details.
Packit 032894
Packit 032894
   You should have received copies of the GNU General Public License and
Packit 032894
   the GNU Lesser General Public License along with this program.  If
Packit 032894
   not, see <http://www.gnu.org/licenses/>.  */
Packit 032894
Packit 032894
#ifdef HAVE_CONFIG_H
Packit 032894
# include <config.h>
Packit 032894
#endif
Packit 032894
Packit 032894
#include <assert.h>
Packit 032894
#include <elf.h>
Packit 032894
#include <stddef.h>
Packit 032894
#include <string.h>
Packit 032894
Packit 032894
#define BACKEND		ppc_
Packit 032894
#include "libebl_CPU.h"
Packit 032894
Packit 032894
Packit 032894
/* Check for the simple reloc types.  */
Packit 032894
Elf_Type
Packit 032894
ppc_reloc_simple_type (Ebl *ebl __attribute__ ((unused)), int type,
Packit 032894
		       int *addsub __attribute__ ((unused)))
Packit 032894
{
Packit 032894
  switch (type)
Packit 032894
    {
Packit 032894
    case R_PPC_ADDR32:
Packit 032894
    case R_PPC_UADDR32:
Packit 032894
      return ELF_T_WORD;
Packit 032894
    case R_PPC_UADDR16:
Packit 032894
      return ELF_T_HALF;
Packit 032894
    default:
Packit 032894
      return ELF_T_NUM;
Packit 032894
    }
Packit 032894
}
Packit 032894
Packit 032894
Packit 032894
/* Check whether machine flags are valid.  */
Packit 032894
bool
Packit 032894
ppc_machine_flag_check (GElf_Word flags)
Packit 032894
{
Packit 032894
  return ((flags &~ (EF_PPC_EMB
Packit 032894
		     | EF_PPC_RELOCATABLE
Packit 032894
		     | EF_PPC_RELOCATABLE_LIB)) == 0);
Packit 032894
}
Packit 032894
Packit 032894
Packit 032894
const char *
Packit 032894
ppc_dynamic_tag_name (int64_t tag, char *buf __attribute__ ((unused)),
Packit 032894
		      size_t len __attribute__ ((unused)))
Packit 032894
{
Packit 032894
  switch (tag)
Packit 032894
    {
Packit 032894
    case DT_PPC_GOT:
Packit 032894
      return "PPC_GOT";
Packit 032894
    case DT_PPC_OPT:
Packit 032894
      return "PPC_OPT";
Packit 032894
    default:
Packit 032894
      break;
Packit 032894
    }
Packit 032894
  return NULL;
Packit 032894
}
Packit 032894
Packit 032894
Packit 032894
bool
Packit 032894
ppc_dynamic_tag_check (int64_t tag)
Packit 032894
{
Packit 032894
  return (tag == DT_PPC_GOT
Packit 032894
	  || tag == DT_PPC_OPT);
Packit 032894
}
Packit 032894
Packit 032894
Packit 032894
/* Look for DT_PPC_GOT.  */
Packit 032894
static bool
Packit 032894
find_dyn_got (Elf *elf, GElf_Addr *addr)
Packit 032894
{
Packit 032894
  size_t phnum;
Packit 032894
  if (elf_getphdrnum (elf, &phnum) != 0)
Packit 032894
    return false;
Packit 032894
Packit 032894
  for (size_t i = 0; i < phnum; ++i)
Packit 032894
    {
Packit 032894
      GElf_Phdr phdr_mem;
Packit 032894
      GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem);
Packit 032894
      if (phdr == NULL || phdr->p_type != PT_DYNAMIC)
Packit 032894
	continue;
Packit 032894
Packit 032894
      Elf_Scn *scn = gelf_offscn (elf, phdr->p_offset);
Packit 032894
      GElf_Shdr shdr_mem;
Packit 032894
      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
Packit 032894
      Elf_Data *data = elf_getdata (scn, NULL);
Packit 032894
      if (shdr != NULL && shdr->sh_type == SHT_DYNAMIC && data != NULL
Packit 032894
	  && shdr->sh_entsize != 0)
Packit 032894
	for (unsigned int j = 0; j < shdr->sh_size / shdr->sh_entsize; ++j)
Packit 032894
	  {
Packit 032894
	    GElf_Dyn dyn_mem;
Packit 032894
	    GElf_Dyn *dyn = gelf_getdyn (data, j, &dyn_mem);
Packit 032894
	    if (dyn != NULL && dyn->d_tag == DT_PPC_GOT)
Packit 032894
	      {
Packit 032894
		*addr = dyn->d_un.d_ptr;
Packit 032894
		return true;
Packit 032894
	      }
Packit 032894
	  }
Packit 032894
Packit 032894
      /* There is only one PT_DYNAMIC entry.  */
Packit 032894
      break;
Packit 032894
    }
Packit 032894
Packit 032894
  return false;
Packit 032894
}
Packit 032894
Packit 032894
Packit 032894
/* Check whether given symbol's st_value and st_size are OK despite failing
Packit 032894
   normal checks.  */
Packit 032894
bool
Packit 032894
ppc_check_special_symbol (Elf *elf, const GElf_Sym *sym,
Packit 032894
			  const char *name, const GElf_Shdr *destshdr)
Packit 032894
{
Packit 032894
  if (name == NULL)
Packit 032894
    return false;
Packit 032894
Packit 032894
  if (strcmp (name, "_GLOBAL_OFFSET_TABLE_") == 0)
Packit 032894
    {
Packit 032894
      /* In -msecure-plt mode, DT_PPC_GOT is present and must match.  */
Packit 032894
      GElf_Addr gotaddr;
Packit 032894
      if (find_dyn_got (elf, &gotaddr))
Packit 032894
	return sym->st_value == gotaddr;
Packit 032894
Packit 032894
      /* In -mbss-plt mode, any place in the section is valid.  */
Packit 032894
      return true;
Packit 032894
    }
Packit 032894
Packit 032894
  size_t shstrndx;
Packit 032894
  if (elf_getshdrstrndx (elf, &shstrndx) != 0)
Packit 032894
    return false;
Packit 032894
  const char *sname = elf_strptr (elf, shstrndx, destshdr->sh_name);
Packit 032894
  if (sname == NULL)
Packit 032894
    return false;
Packit 032894
Packit 032894
  /* Small data area.  Normally points to .sdata, in which case we
Packit 032894
     check it is at an offset of 0x8000.  It might however fall in the
Packit 032894
     .data section, in which case we cannot check the offset.  The
Packit 032894
     size always should be zero.  */
Packit 032894
  if (strcmp (name, "_SDA_BASE_") == 0)
Packit 032894
    return (((strcmp (sname, ".sdata") == 0
Packit 032894
	      && sym->st_value == destshdr->sh_addr + 0x8000)
Packit 032894
	     || strcmp (sname, ".data") == 0)
Packit 032894
	    && sym->st_size == 0);
Packit 032894
Packit 032894
  if (strcmp (name, "_SDA2_BASE_") == 0)
Packit 032894
    return (strcmp (sname, ".sdata2") == 0
Packit 032894
	    && sym->st_value == destshdr->sh_addr + 0x8000
Packit 032894
	    && sym->st_size == 0);
Packit 032894
Packit 032894
  return false;
Packit 032894
}
Packit 032894
Packit 032894
Packit 032894
/* Check if backend uses a bss PLT in this file.  */
Packit 032894
bool
Packit 032894
ppc_bss_plt_p (Elf *elf)
Packit 032894
{
Packit 032894
  GElf_Addr addr;
Packit 032894
  return ! find_dyn_got (elf, &addr);
Packit 032894
}