Tue Jun 18 14:42:58 1996 Klaus Kaempf <kkaempf@progis.de>
[deliverable/binutils-gdb.git] / bfd / elf.c
index 05254ff68f353a759339e8b89df100758b397d1f..599706794b3aea220aadadeaedc437e045783f7e 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -1,5 +1,5 @@
 /* ELF executable support for BFD.
-   Copyright 1993 Free Software Foundation, Inc.
+   Copyright 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
 
 This file is part of BFD, the Binary File Descriptor library.
 
@@ -39,7 +39,7 @@ SECTION
 #include "elf-bfd.h"
 
 static INLINE struct elf_segment_map *make_mapping
-  PARAMS ((bfd *, asection **, unsigned int, unsigned int));
+  PARAMS ((bfd *, asection **, unsigned int, unsigned int, boolean));
 static int elf_sort_sections PARAMS ((const PTR, const PTR));
 static boolean assign_file_positions_for_segments PARAMS ((bfd *));
 static boolean assign_file_positions_except_relocs PARAMS ((bfd *));
@@ -335,50 +335,152 @@ _bfd_elf_print_private_bfd_data (abfd, farg)
 {
   FILE *f = (FILE *) farg;
   Elf_Internal_Phdr *p;
-  unsigned int i, c;
+  asection *s;
+  bfd_byte *dynbuf = NULL;
 
   p = elf_tdata (abfd)->phdr;
-  if (p == NULL)
-    return true;
+  if (p != NULL)
+    {
+      unsigned int i, c;
 
-  c = elf_elfheader (abfd)->e_phnum;
-  for (i = 0; i < c; i++, p++)
+      fprintf (f, "\nProgram Header:\n");
+      c = elf_elfheader (abfd)->e_phnum;
+      for (i = 0; i < c; i++, p++)
+       {
+         const char *s;
+         char buf[20];
+
+         switch (p->p_type)
+           {
+           case PT_NULL: s = "NULL"; break;
+           case PT_LOAD: s = "LOAD"; break;
+           case PT_DYNAMIC: s = "DYNAMIC"; break;
+           case PT_INTERP: s = "INTERP"; break;
+           case PT_NOTE: s = "NOTE"; break;
+           case PT_SHLIB: s = "SHLIB"; break;
+           case PT_PHDR: s = "PHDR"; break;
+           default: sprintf (buf, "0x%lx", p->p_type); s = buf; break;
+           }
+         fprintf (f, "%8s off    0x", s);
+         fprintf_vma (f, p->p_offset);
+         fprintf (f, " vaddr 0x");
+         fprintf_vma (f, p->p_vaddr);
+         fprintf (f, " paddr 0x");
+         fprintf_vma (f, p->p_paddr);
+         fprintf (f, " align 2**%u\n", bfd_log2 (p->p_align));
+         fprintf (f, "         filesz 0x");
+         fprintf_vma (f, p->p_filesz);
+         fprintf (f, " memsz 0x");
+         fprintf_vma (f, p->p_memsz);
+         fprintf (f, " flags %c%c%c",
+                  (p->p_flags & PF_R) != 0 ? 'r' : '-',
+                  (p->p_flags & PF_W) != 0 ? 'w' : '-',
+                  (p->p_flags & PF_X) != 0 ? 'x' : '-');
+         if ((p->p_flags &~ (PF_R | PF_W | PF_X)) != 0)
+           fprintf (f, " %lx", p->p_flags &~ (PF_R | PF_W | PF_X));
+         fprintf (f, "\n");
+       }
+    }
+
+  s = bfd_get_section_by_name (abfd, ".dynamic");
+  if (s != NULL)
     {
-      const char *s;
-      char buf[20];
+      int elfsec;
+      unsigned long link;
+      bfd_byte *extdyn, *extdynend;
+      size_t extdynsize;
+      void (*swap_dyn_in) PARAMS ((bfd *, const PTR, Elf_Internal_Dyn *));
+
+      fprintf (f, "\nDynamic Section:\n");
+
+      dynbuf = (bfd_byte *) bfd_malloc (s->_raw_size);
+      if (dynbuf == NULL)
+       goto error_return;
+      if (! bfd_get_section_contents (abfd, s, (PTR) dynbuf, (file_ptr) 0,
+                                     s->_raw_size))
+       goto error_return;
+
+      elfsec = _bfd_elf_section_from_bfd_section (abfd, s);
+      if (elfsec == -1)
+       goto error_return;
+      link = elf_elfsections (abfd)[elfsec]->sh_link;
+
+      extdynsize = get_elf_backend_data (abfd)->s->sizeof_dyn;
+      swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in;
 
-      switch (p->p_type)
+      extdyn = dynbuf;
+      extdynend = extdyn + s->_raw_size;
+      for (; extdyn < extdynend; extdyn += extdynsize)
        {
-       case PT_NULL: s = "NULL"; break;
-       case PT_LOAD: s = "LOAD"; break;
-       case PT_DYNAMIC: s = "DYNAMIC"; break;
-       case PT_INTERP: s = "INTERP"; break;
-       case PT_NOTE: s = "NOTE"; break;
-       case PT_SHLIB: s = "SHLIB"; break;
-       case PT_PHDR: s = "PHDR"; break;
-       default: sprintf (buf, "0x%lx", p->p_type); s = buf; break;
+         Elf_Internal_Dyn dyn;
+         const char *name;
+         char ab[20];
+         boolean stringp;
+
+         (*swap_dyn_in) (abfd, (PTR) extdyn, &dyn);
+
+         if (dyn.d_tag == DT_NULL)
+           break;
+
+         stringp = false;
+         switch (dyn.d_tag)
+           {
+           default:
+             sprintf (ab, "0x%lx", (unsigned long) dyn.d_tag);
+             name = ab;
+             break;
+
+           case DT_NEEDED: name = "NEEDED"; stringp = true; break;
+           case DT_PLTRELSZ: name = "PLTRELSZ"; break;
+           case DT_PLTGOT: name = "PLTGOT"; break;
+           case DT_HASH: name = "HASH"; break;
+           case DT_STRTAB: name = "STRTAB"; break;
+           case DT_SYMTAB: name = "SYMTAB"; break;
+           case DT_RELA: name = "RELA"; break;
+           case DT_RELASZ: name = "RELASZ"; break;
+           case DT_RELAENT: name = "RELAENT"; break;
+           case DT_STRSZ: name = "STRSZ"; break;
+           case DT_SYMENT: name = "SYMENT"; break;
+           case DT_INIT: name = "INIT"; break;
+           case DT_FINI: name = "FINI"; break;
+           case DT_SONAME: name = "SONAME"; stringp = true; break;
+           case DT_RPATH: name = "RPATH"; stringp = true; break;
+           case DT_SYMBOLIC: name = "SYMBOLIC"; break;
+           case DT_REL: name = "REL"; break;
+           case DT_RELSZ: name = "RELSZ"; break;
+           case DT_RELENT: name = "RELENT"; break;
+           case DT_PLTREL: name = "PLTREL"; break;
+           case DT_DEBUG: name = "DEBUG"; break;
+           case DT_TEXTREL: name = "TEXTREL"; break;
+           case DT_JMPREL: name = "JMPREL"; break;
+           }
+
+         fprintf (f, "  %-11s ", name);
+         if (! stringp)
+           fprintf (f, "0x%lx", (unsigned long) dyn.d_un.d_val);
+         else
+           {
+             const char *string;
+
+             string = bfd_elf_string_from_elf_section (abfd, link,
+                                                       dyn.d_un.d_val);
+             if (string == NULL)
+               goto error_return;
+             fprintf (f, "%s", string);
+           }
+         fprintf (f, "\n");
        }
-      fprintf (f, "%8s off    0x", s);
-      fprintf_vma (f, p->p_offset);
-      fprintf (f, " vaddr 0x");
-      fprintf_vma (f, p->p_vaddr);
-      fprintf (f, " paddr 0x");
-      fprintf_vma (f, p->p_paddr);
-      fprintf (f, " align 2**%u\n", bfd_log2 (p->p_align));
-      fprintf (f, "         filesz 0x");
-      fprintf_vma (f, p->p_filesz);
-      fprintf (f, " memsz 0x");
-      fprintf_vma (f, p->p_memsz);
-      fprintf (f, " flags %c%c%c",
-              (p->p_flags & PF_R) != 0 ? 'r' : '-',
-              (p->p_flags & PF_W) != 0 ? 'w' : '-',
-              (p->p_flags & PF_X) != 0 ? 'x' : '-');
-      if ((p->p_flags &~ (PF_R | PF_W | PF_X)) != 0)
-       fprintf (f, " %lx", p->p_flags &~ (PF_R | PF_W | PF_X));
-      fprintf (f, "\n");
+
+      free (dynbuf);
+      dynbuf = NULL;
     }
 
   return true;
+
+ error_return:
+  if (dynbuf != NULL)
+    free (dynbuf);
+  return false;
 }
 
 /* Display ELF-specific fields of a symbol.  */
@@ -452,8 +554,13 @@ _bfd_elf_link_hash_newfunc (entry, table, string)
       ret->weakdef = NULL;
       ret->got_offset = (bfd_vma) -1;
       ret->plt_offset = (bfd_vma) -1;
+      ret->linker_section_pointer = (elf_linker_section_pointers_t *)0;
       ret->type = STT_NOTYPE;
-      ret->elf_link_hash_flags = 0;
+      /* Assume that we have been called by a non-ELF symbol reader.
+         This flag is then reset by the code which reads an ELF input
+         file.  This ensures that a symbol created by a non-ELF symbol
+         reader will have the flag set correctly.  */
+      ret->elf_link_hash_flags = ELF_LINK_NON_ELF;
     }
 
   return (struct bfd_hash_entry *) ret;
@@ -476,6 +583,8 @@ _bfd_elf_link_hash_table_init (table, abfd, newfunc)
   table->dynstr = NULL;
   table->bucketcount = 0;
   table->needed = NULL;
+  table->hgot = NULL;
+  table->stab_info = NULL;
   return _bfd_link_hash_table_init (&table->root, abfd, newfunc);
 }
 
@@ -511,11 +620,13 @@ bfd_elf_set_dt_needed_name (abfd, name)
      bfd *abfd;
      const char *name;
 {
-  if (bfd_get_flavour (abfd) == bfd_target_elf_flavour)
-    elf_dt_needed_name (abfd) = name;
+  if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
+      && bfd_get_format (abfd) == bfd_object)
+    elf_dt_name (abfd) = name;
 }
 
-/* Get the list of DT_NEEDED entries for a link.  */
+/* Get the list of DT_NEEDED entries for a link.  This is a hook for
+   the ELF emulation code.  */
 
 struct bfd_link_needed_list *
 bfd_elf_get_needed_list (abfd, info)
@@ -526,6 +637,20 @@ bfd_elf_get_needed_list (abfd, info)
     return NULL;
   return elf_hash_table (info)->needed;
 }
+
+/* Get the name actually used for a dynamic object for a link.  This
+   is the SONAME entry if there is one.  Otherwise, it is the string
+   passed to bfd_elf_set_dt_needed_name, or it is the filename.  */
+
+const char *
+bfd_elf_get_dt_soname (abfd)
+     bfd *abfd;
+{
+  if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
+      && bfd_get_format (abfd) == bfd_object)
+    return elf_dt_name (abfd);
+  return NULL;
+}
 \f
 /* Allocate an ELF string table--force the first byte to be zero.  */
 
@@ -676,7 +801,6 @@ bfd_section_from_shdr (abfd, shindex)
       {
        asection *target_sect;
        Elf_Internal_Shdr *hdr2;
-       int use_rela_p = get_elf_backend_data (abfd)->use_rela_p;
 
        /* For some incomprehensible reason Oracle distributes
           libraries for Solaris in which some of the objects have
@@ -721,30 +845,24 @@ bfd_section_from_shdr (abfd, shindex)
        if (hdr->sh_link != elf_onesymtab (abfd))
          return _bfd_elf_make_section_from_shdr (abfd, hdr, name);
 
-       /* Don't allow REL relocations on a machine that uses RELA and
-          vice versa.  */
-       /* @@ Actually, the generic ABI does suggest that both might be
-          used in one file.  But the four ABI Processor Supplements I
-          have access to right now all specify that only one is used on
-          each of those architectures.  It's conceivable that, e.g., a
-          bunch of absolute 32-bit relocs might be more compact in REL
-          form even on a RELA machine...  */
-       BFD_ASSERT (use_rela_p
-                   ? (hdr->sh_type == SHT_RELA
-                      && hdr->sh_entsize == bed->s->sizeof_rela)
-                   : (hdr->sh_type == SHT_REL
-                      && hdr->sh_entsize == bed->s->sizeof_rel));
-
        if (! bfd_section_from_shdr (abfd, hdr->sh_info))
          return false;
        target_sect = bfd_section_from_elf_index (abfd, hdr->sh_info);
        if (target_sect == NULL)
          return false;
 
-       hdr2 = &elf_section_data (target_sect)->rel_hdr;
+       if ((target_sect->flags & SEC_RELOC) == 0
+           || target_sect->reloc_count == 0)
+         hdr2 = &elf_section_data (target_sect)->rel_hdr;
+       else
+         {
+           BFD_ASSERT (elf_section_data (target_sect)->rel_hdr2 == NULL);
+           hdr2 = (Elf_Internal_Shdr *) bfd_alloc (abfd, sizeof (*hdr2));
+           elf_section_data (target_sect)->rel_hdr2 = hdr2;
+         }
        *hdr2 = *hdr;
        elf_elfsections (abfd)[shindex] = hdr2;
-       target_sect->reloc_count = hdr->sh_size / hdr->sh_entsize;
+       target_sect->reloc_count += hdr->sh_size / hdr->sh_entsize;
        target_sect->flags |= SEC_RELOC;
        target_sect->relocation = NULL;
        target_sect->rel_filepos = hdr->sh_offset;
@@ -1485,11 +1603,12 @@ _bfd_elf_compute_section_file_positions (abfd, link_info)
 /* Create a mapping from a set of sections to a program segment.  */
 
 static INLINE struct elf_segment_map *
-make_mapping (abfd, sections, from, to)
+make_mapping (abfd, sections, from, to, phdr)
      bfd *abfd;
      asection **sections;
      unsigned int from;
      unsigned int to;
+     boolean phdr;
 {
   struct elf_segment_map *m;
   unsigned int i;
@@ -1507,7 +1626,7 @@ make_mapping (abfd, sections, from, to)
     m->sections[i - from] = *hdrpp;
   m->count = to - from;
 
-  if (from == 0)
+  if (from == 0 && phdr)
     {
       /* Include the headers in the first PT_LOAD segment.  */
       m->includes_filehdr = 1;
@@ -1534,6 +1653,9 @@ map_sections_to_segments (abfd)
   unsigned int phdr_index;
   bfd_vma maxpagesize;
   asection **hdrpp;
+  boolean phdr_in_section = true;
+  boolean writable;
+  asection *dynsec;
 
   if (elf_tdata (abfd)->segment_map != NULL)
     return true;
@@ -1606,6 +1728,19 @@ map_sections_to_segments (abfd)
   last_hdr = NULL;
   phdr_index = 0;
   maxpagesize = get_elf_backend_data (abfd)->maxpagesize;
+  writable = false;
+  dynsec = bfd_get_section_by_name (abfd, ".dynamic");
+  if (dynsec != NULL
+      && (dynsec->flags & SEC_LOAD) == 0)
+    dynsec = NULL;
+
+  /* Deal with -Ttext or something similar such that the
+     first section is not adjacent to the program headers.  */
+  if (count
+      && ((sections[0]->lma % maxpagesize) <
+         (elf_tdata (abfd)->program_header_size % maxpagesize)))
+    phdr_in_section = false;
+
   for (i = 0, hdrpp = sections; i < count; i++, hdrpp++)
     {
       asection *hdr;
@@ -1613,12 +1748,20 @@ map_sections_to_segments (abfd)
       hdr = *hdrpp;
 
       /* See if this section and the last one will fit in the same
-         segment.  */
+         segment.  Don't put a loadable section after a non-loadable
+         section.  If we are building a dynamic executable, don't put
+         a writable section in a read only segment (we don't do this
+         for a non-dynamic executable because some people prefer to
+         have only one program segment; anybody can use PHDRS in their
+         linker script to control what happens anyhow).  */
       if (last_hdr == NULL
          || ((BFD_ALIGN (last_hdr->lma + last_hdr->_raw_size, maxpagesize)
               >= hdr->lma)
              && ((last_hdr->flags & SEC_LOAD) != 0
-                 || (hdr->flags & SEC_LOAD) == 0)))
+                 || (hdr->flags & SEC_LOAD) == 0)
+             && (dynsec == NULL
+                 || writable
+                 || (hdr->flags & SEC_READONLY) != 0)))
        {
          last_hdr = hdr;
          continue;
@@ -1628,21 +1771,25 @@ map_sections_to_segments (abfd)
          create a new program header holding all the sections from
          phdr_index until hdr.  */
 
-      m = make_mapping (abfd, sections, phdr_index, i);
+      m = make_mapping (abfd, sections, phdr_index, i, phdr_in_section);
       if (m == NULL)
        goto error_return;
 
       *pm = m;
       pm = &m->next;
 
+      if ((hdr->flags & SEC_READONLY) == 0)
+       writable = true;
+
       last_hdr = hdr;
       phdr_index = i;
+      phdr_in_section = false;
     }
 
   /* Create a final PT_LOAD program segment.  */
   if (last_hdr != NULL)
     {
-      m = make_mapping (abfd, sections, phdr_index, i);
+      m = make_mapping (abfd, sections, phdr_index, i, phdr_in_section);
       if (m == NULL)
        goto error_return;
 
@@ -1651,8 +1798,7 @@ map_sections_to_segments (abfd)
     }
 
   /* If there is a .dynamic section, throw in a PT_DYNAMIC segment.  */
-  s = bfd_get_section_by_name (abfd, ".dynamic");
-  if (s != NULL && (s->flags & SEC_LOAD) != 0)
+  if (dynsec != NULL)
     {
       m = ((struct elf_segment_map *)
           bfd_zalloc (abfd, sizeof (struct elf_segment_map)));
@@ -1661,7 +1807,7 @@ map_sections_to_segments (abfd)
       m->next = NULL;
       m->p_type = PT_DYNAMIC;
       m->count = 1;
-      m->sections[0] = s;
+      m->sections[0] = dynsec;
 
       *pm = m;
       pm = &m->next;
@@ -1806,8 +1952,12 @@ assign_file_positions_for_segments (abfd)
 
       if (m->p_flags_valid)
        p->p_flags = m->p_flags;
+      else
+       p->p_flags = 0;
 
-      if (p->p_type == PT_LOAD && m->count > 0)
+      if (p->p_type == PT_LOAD
+         && m->count > 0
+         && (m->sections[0]->flags & SEC_LOAD) != 0)
        off += (m->sections[0]->vma - off) % bed->maxpagesize;
 
       if (m->count == 0)
@@ -1835,6 +1985,8 @@ assign_file_positions_for_segments (abfd)
 
       if (m->includes_filehdr)
        {
+         if (! m->p_flags_valid)
+           p->p_flags |= PF_R;
          p->p_offset = 0;
          p->p_filesz = bed->s->sizeof_ehdr;
          p->p_memsz = bed->s->sizeof_ehdr;
@@ -1854,6 +2006,8 @@ assign_file_positions_for_segments (abfd)
 
       if (m->includes_phdrs)
        {
+         if (! m->p_flags_valid)
+           p->p_flags |= PF_R;
          if (m->includes_filehdr)
            {
              if (p->p_type == PT_LOAD)
@@ -1896,8 +2050,6 @@ assign_file_positions_for_segments (abfd)
            }
        }
 
-      if (! m->p_flags_valid)
-       p->p_flags = PF_R;
       for (i = 0, secpp = m->sections; i < m->count; i++, secpp++)
        {
          asection *sec;
@@ -1913,15 +2065,18 @@ assign_file_positions_for_segments (abfd)
 
              /* The section VMA must equal the file position modulo
                  the page size.  */
-             adjust = (sec->vma - off) % bed->maxpagesize;
-             if (adjust != 0)
+             if ((flags & SEC_ALLOC) != 0)
                {
-                 if (i == 0)
-                   abort ();
-                 p->p_memsz += adjust;
-                 if ((flags & SEC_LOAD) != 0)
-                   p->p_filesz += adjust;
-                 off += adjust;
+                 adjust = (sec->vma - off) % bed->maxpagesize;
+                 if (adjust != 0)
+                   {
+                     if (i == 0)
+                       abort ();
+                     p->p_memsz += adjust;
+                     off += adjust;
+                     if ((flags & SEC_LOAD) != 0)
+                       p->p_filesz += adjust;
+                   }
                }
 
              sec->filepos = off;
@@ -1941,6 +2096,7 @@ assign_file_positions_for_segments (abfd)
 
          if (! m->p_flags_valid)
            {
+             p->p_flags |= PF_R;
              if ((flags & SEC_CODE) != 0)
                p->p_flags |= PF_X;
              if ((flags & SEC_READONLY) == 0)
@@ -2420,8 +2576,10 @@ _bfd_elf_section_from_bfd_section (abfd, asect)
   return -1;
 }
 
-/* given a symbol, return the bfd index for that symbol.  */
- int
+/* Given a BFD symbol, return the index in the ELF symbol table, or -1
+   on error.  */
+
+int
 _bfd_elf_symbol_from_bfd_symbol (abfd, asym_ptr_ptr)
      bfd *abfd;
      struct symbol_cache_entry **asym_ptr_ptr;
@@ -2450,13 +2608,24 @@ _bfd_elf_symbol_from_bfd_symbol (abfd, asym_ptr_ptr)
     }
 
   idx = asym_ptr->udata.i;
-  BFD_ASSERT (idx != 0);
+
+  if (idx == 0)
+    {
+      /* This case can occur when using --strip-symbol on a symbol
+         which is used in a relocation entry.  */
+      (*_bfd_error_handler)
+       ("%s: symbol `%s' required but not present",
+        bfd_get_filename (abfd), bfd_asymbol_name (asym_ptr));
+      bfd_set_error (bfd_error_no_symbols);
+      return -1;
+    }
 
 #if DEBUG & 4
   {
     fprintf (stderr,
             "elf_symbol_from_bfd_symbol 0x%.8lx, name = %s, sym num = %d, flags = 0x%.8lx%s\n",
-     (long) asym_ptr, asym_ptr->name, idx, flags, elf_symbol_flags (flags));
+            (long) asym_ptr, asym_ptr->name, idx, flags,
+            elf_symbol_flags (flags));
     fflush (stderr);
   }
 #endif
@@ -2724,6 +2893,7 @@ swap_out_syms (abfd, sttp)
        bfd_vma value = syms[idx]->value;
        elf_symbol_type *type_ptr;
        flagword flags = syms[idx]->flags;
+       int type;
 
        if (flags & BSF_SECTION_SYM)
          /* Section symbols have no names.  */
@@ -2818,15 +2988,20 @@ swap_out_syms (abfd, sttp)
            sym.st_shndx = shndx;
          }
 
+       if ((flags & BSF_FUNCTION) != 0)
+         type = STT_FUNC;
+       else if ((flags & BSF_OBJECT) != 0)
+         type = STT_OBJECT;
+       else
+         type = STT_NOTYPE;
+
        if (bfd_is_com_section (syms[idx]->section))
-         sym.st_info = ELF_ST_INFO (STB_GLOBAL, STT_OBJECT);
+         sym.st_info = ELF_ST_INFO (STB_GLOBAL, type);
        else if (bfd_is_und_section (syms[idx]->section))
          sym.st_info = ELF_ST_INFO (((flags & BSF_WEAK)
                                      ? STB_WEAK
                                      : STB_GLOBAL),
-                                    ((flags & BSF_FUNCTION)
-                                     ? STT_FUNC
-                                     : STT_NOTYPE));
+                                    type);
        else if (flags & BSF_SECTION_SYM)
          sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
        else if (flags & BSF_FILE)
@@ -2834,7 +3009,6 @@ swap_out_syms (abfd, sttp)
        else
          {
            int bind = STB_LOCAL;
-           int type = STT_OBJECT;
 
            if (flags & BSF_LOCAL)
              bind = STB_LOCAL;
@@ -2843,9 +3017,6 @@ swap_out_syms (abfd, sttp)
            else if (flags & BSF_GLOBAL)
              bind = STB_GLOBAL;
 
-           if (flags & BSF_FUNCTION)
-             type = STT_FUNC;
-
            sym.st_info = ELF_ST_INFO (bind, type);
          }
 
@@ -3030,15 +3201,26 @@ _bfd_elf_find_nearest_line (abfd,
      CONST char **functionname_ptr;
      unsigned int *line_ptr;
 {
+  boolean found;
   const char *filename;
   asymbol *func;
+  bfd_vma low_func;
   asymbol **p;
 
+  if (! _bfd_stab_section_find_nearest_line (abfd, symbols, section, offset,
+                                            &found, filename_ptr,
+                                            functionname_ptr, line_ptr,
+                                            &elf_tdata (abfd)->line_info))
+    return false;
+  if (found)
+    return true;
+
   if (symbols == NULL)
     return false;
 
   filename = NULL;
   func = NULL;
+  low_func = 0;
 
   for (p = symbols; *p != NULL; p++)
     {
@@ -3057,9 +3239,13 @@ _bfd_elf_find_nearest_line (abfd,
          filename = bfd_asymbol_name (&q->symbol);
          break;
        case STT_FUNC:
-         if (func == NULL
-             || q->symbol.value <= offset)
-           func = (asymbol *) q;
+         if (q->symbol.section == section
+             && q->symbol.value >= low_func
+             && q->symbol.value <= offset)
+           {
+             func = (asymbol *) q;
+             low_func = q->symbol.value;
+           }
          break;
        }
     }
This page took 0.030857 seconds and 4 git commands to generate.