The Pedigree Project  0.1
ppc/DynamicLinker.cc
1 /*
2  * Copyright (c) 2008-2014, Pedigree Developers
3  *
4  * Please see the CONTRIB file in the root of the source tree for a full
5  * list of contributors.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include "DynamicLinker.h"
21 #include "modules/Module.h"
22 #include "modules/system/vfs/VFS.h"
23 #include "pedigree/kernel/Log.h"
24 #include "pedigree/kernel/panic.h"
25 #include "pedigree/kernel/process/Scheduler.h"
26 #include "pedigree/kernel/processor/KernelCoreSyscallManager.h"
27 #include "pedigree/kernel/processor/PhysicalMemoryManager.h"
28 #include "pedigree/kernel/processor/Processor.h"
29 #include "pedigree/kernel/processor/VirtualAddressSpace.h"
30 #include "pedigree/kernel/utilities/StaticString.h"
31 
32 extern "C" void plt_resolve(void);
33 
34 #define HA(x) (((x >> 16) + ((x & 0x8000) ? 1 : 0)) & 0xFFFF)
35 
36 void DynamicLinker::initPlt(Elf *pElf, uintptr_t value)
37 {
38  // The PLT on PowerPC is structured differently to i686. The first 18 words
39  // (72 bytes) are reserved for the dynamic linker (us). In there, we copy
40  // the contents of ./asm-ppc.s. After that comes the PLT itself. It's not
41  // initialised - we must do that ourselves. We get two words in each entry
42  // to play with. Ather that comes the PLT table - it's a table at the end of
43  // the PLT, one word for each entry. In here we put the address of the
44  // resolved symbol location, and 'plt_call' uses that to jump correctly.
45 
46  // The PLTGOT entry in the Elf's dynamic structure which usually represents
47  // the GOT address in PPC gives the PLT address.
48  uintptr_t prePlt = pElf->getGlobalOffsetTable();
49  uintptr_t pltEntries = prePlt + 72;
50  uintptr_t pltSize = pElf->getPltSize();
51  uintptr_t postPlt = pltEntries + pltSize;
52 
53  if (prePlt == value)
54  return; // No PLT.
55 
56  // Memcpy over the pre-plt functions into the user address space.
57  // plt_resolve is an ASM function, defined in ./asm-ppc.s
58  MemoryCopy(
59  reinterpret_cast<uint8_t *>(prePlt),
60  reinterpret_cast<uint8_t *>(&::plt_resolve),
61  72); // 72 bytes exactly. See ELF spec.
62 
63  // There are 4 words in the stub we just copied that need relocation:
64  // addis 4, 0, 0 # 4 -- These will be filled in by the pltInit function
65  // addi 4, 4, 0 # 5 -- to be a library identifier.
66  //
67  // addis 11, 11, 0 # 13 -- These get filled in by the pltInit function
68  // lwz 11, 0(11) # 14 -- to be the address of the PLT table.
69 
70  uint32_t *pWord = (uint32_t *) (prePlt + 4 * 4);
71  *pWord = (*pWord) | HA(value);
72 
73  pWord++;
74  *pWord = (*pWord) | (value & 0xFFFF);
75 
76  pWord = (uint32_t *) (prePlt + 13 * 4);
77  *pWord = (*pWord) | HA(postPlt);
78 
79  pWord++;
80  *pWord = (*pWord) | (postPlt & 0xFFFF);
81 
82  // Each PLT entry consists of an addi and a branch;
83  // plt$i:
84  // addi r11, r0, 4*$i
85  // b plt_resolve (which is located at prePlt+0)
86 
87  for (int i = 0; i < pltSize / 8; i++)
88  {
89  // 1111111111222222222233
90  // ADDI: 01234567890123456789012345678901
91  // OPC---DEST-ADD--IMMEDIATE-------
92  // 0b0011100101100000---IMMEDIATE----
93  // 0x3 9 6 0
94  uint32_t addi = 0x39600000 | (4 * i);
95 
96  // 1111111111222222222233
97  // B: 01234567890123456789012345678901
98  // OPC---LI----------------------AL
99  // 0b010010---IMMEDIATE------------00
100  // 0x4 8
101  int32_t offset = (int32_t) postPlt - (int32_t)(pltEntries + 8 * i + 4);
102  uint32_t b = 0x48000000 | offset;
103 
104  uint32_t *pEntry = (uint32_t *) (pltEntries + i * 8);
105  *pEntry++ = addi;
106  *pEntry = b;
107  }
108 }
109 
110 uintptr_t DynamicLinker::resolvePltSymbol(uintptr_t libraryId, uintptr_t symIdx)
111 {
112  // Find the correct ELF to patch.
113  Elf *pElf = 0;
114  Elf *pOrigElf = 0;
115  uintptr_t loadBase = 0;
116 
117  pOrigElf = m_ProcessElfs.lookup(
118  Processor::information().getCurrentThread()->getParent());
119 
120  if (libraryId == 0)
121  pElf = m_ProcessElfs.lookup(
122  Processor::information().getCurrentThread()->getParent());
123  else
124  {
125  // Library search.
126  // Grab the list of loaded shared objects for this process.
127  List<SharedObject *> *pList = m_ProcessObjects.lookup(
128  Processor::information().getCurrentThread()->getParent());
129 
130  // Look through the shared object list.
131  for (List<SharedObject *>::Iterator it = pList->begin();
132  it != pList->end(); it++)
133  {
134  pElf = findElf(libraryId, *it, loadBase);
135  if (pElf != 0)
136  break;
137  }
138  }
139 
141  uintptr_t result = pElf->applySpecificRelocation(
142  symIdx / 4, pOrigElf->getSymbolTable(), loadBase,
144 
145  return result;
146 }
static ProcessorInformation & information()
Definition: Processor.cc:45
Definition: List.h:64
uintptr_t resolvePltSymbol(uintptr_t libraryId, uintptr_t symIdx)
size_t getPltSize()
Definition: linker/Elf.cc:1403
::Iterator< T, node_t > Iterator
Definition: List.h:71
Iterator begin()
Definition: List.h:123
uintptr_t applySpecificRelocation(uintptr_t off, SymbolTable *pSymtab, uintptr_t loadBase, SymbolTable::Policy policy=SymbolTable::LocalFirst)
Definition: linker/Elf.cc:1353
uintptr_t getGlobalOffsetTable()
Definition: linker/Elf.cc:1230
Definition: Elf.h:201
Iterator end()
Definition: List.h:135
void initPlt(Elf *pElf, uintptr_t value)