1 /* Run-time dynamic linker data structures for loaded ELF shared objects.
2    Copyright (C) 2005-2022 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4 
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9 
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <https://www.gnu.org/licenses/>.  */
18 
19 #ifndef	_LDSODEFS_H
20 
21 /* Get the real definitions.  */
22 #include_next <ldsodefs.h>
23 
24 /* Now define our stuff.  */
25 
26 #if _CALL_ELF != 2
27 
28 static __always_inline bool
_dl_ppc64_is_opd_sym(const struct link_map * l,const ElfW (Sym)* sym)29 _dl_ppc64_is_opd_sym (const struct link_map *l, const ElfW(Sym) *sym)
30 {
31   return (ELFW(ST_TYPE) (sym->st_info) == STT_FUNC
32 	  && l->l_addr + sym->st_value >= (ElfW(Addr)) l->l_ld
33 	  && l->l_addr + sym->st_value < l->l_map_end
34 	  && sym->st_size != 0);
35 }
36 
37 static __always_inline bool
_dl_ppc64_addr_sym_match(const struct link_map * l,const ElfW (Sym)* sym,const ElfW (Sym)* matchsym,ElfW (Addr)addr)38 _dl_ppc64_addr_sym_match (const struct link_map *l, const ElfW(Sym) *sym,
39 			  const ElfW(Sym) *matchsym, ElfW(Addr) addr)
40 {
41   ElfW(Addr) value = l->l_addr + sym->st_value;
42   if (_dl_ppc64_is_opd_sym (l, sym))
43     {
44       if (addr < value || addr >= value + 24)
45 	{
46 	  value = *(ElfW(Addr) *) value;
47 	  if (addr < value || addr >= value + sym->st_size)
48 	    return false;
49 	}
50     }
51   else if (sym->st_shndx == SHN_UNDEF || sym->st_size == 0)
52     {
53       if (addr != value)
54 	return false;
55     }
56   else if (addr < value || addr >= value + sym->st_size)
57     return false;
58 
59   if (matchsym == NULL)
60     return true;
61 
62   ElfW(Addr) matchvalue = l->l_addr + matchsym->st_value;
63   if (_dl_ppc64_is_opd_sym (l, matchsym)
64       && (addr < matchvalue || addr > matchvalue + 24))
65     matchvalue = *(ElfW(Addr) *) matchvalue;
66 
67   return matchvalue < value;
68 }
69 
70 /* If this is a function symbol defined past the end of our dynamic
71    section, then it must be a function descriptor.  Allow these symbols
72    to match their associated function code range as well as the
73    descriptor addresses.  */
74 #undef DL_ADDR_SYM_MATCH
75 #define DL_ADDR_SYM_MATCH(L, SYM, MATCHSYM, ADDR) \
76   _dl_ppc64_addr_sym_match (L, SYM, MATCHSYM, ADDR)
77 
78 #endif
79 
80 #endif /* ldsodefs.h */
81