Skip to content

Commit 065e5b0

Browse files
committed
GP-3707 revised and implemented missing RISCV ELF relocations.
Corrected ElfRelocation to maintain signed addend value.
1 parent 1ba91eb commit 065e5b0

File tree

3 files changed

+196
-127
lines changed

3 files changed

+196
-127
lines changed

Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfRelocation.java

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ public class ElfRelocation implements StructConverter {
8585

8686
private long r_offset;
8787
private long r_info;
88-
private long r_addend;
88+
private long r_addend; // signed-value
8989

9090
private boolean hasAddend;
9191
private boolean is32bit;
@@ -116,7 +116,7 @@ static ElfRelocation createElfRelocation(BinaryReader reader,
116116
* @param withAddend true if if RELA entry with addend, else false
117117
* @param r_offset The offset for the entry
118118
* @param r_info The info value for the entry
119-
* @param r_addend The addend for the entry
119+
* @param r_addend The signed-addend for the entry (32-bit addends should be signed-extended to 64-bits)
120120
* @return ELF relocation object
121121
* @throws IOException if an IO or parse error occurs
122122
*/
@@ -193,7 +193,8 @@ protected void initElfRelocation(BinaryReader reader, ElfHeader elfHeader,
193193
* @param withAddend true if if RELA entry with addend, else false
194194
* @param offset The offset for the entry (r_offset)
195195
* @param info The info value for the entry (r_info)
196-
* @param addend The addend for the entry (r_addend)
196+
* @param addend The signed-addend (r_addend) for the entry (32-bit addends should
197+
* be signed-extended to 64-bits)
197198
* @throws IOException if an IO or parse error occurs
198199
*/
199200
protected void initElfRelocation(ElfHeader elfHeader, int relocationTableIndex,
@@ -205,16 +206,13 @@ protected void initElfRelocation(ElfHeader elfHeader, int relocationTableIndex,
205206
if (is32bit) {
206207
this.r_offset = Integer.toUnsignedLong((int) offset);
207208
this.r_info = Integer.toUnsignedLong((int) info);
208-
if (hasAddend) {
209-
this.r_addend = Integer.toUnsignedLong((int) addend);
210-
}
211209
}
212210
else {
213211
this.r_offset = offset;
214212
this.r_info = info;
215-
if (hasAddend) {
216-
this.r_addend = addend;
217-
}
213+
}
214+
if (hasAddend) {
215+
this.r_addend = addend;
218216
}
219217
}
220218

@@ -223,7 +221,7 @@ private void readEntryData(BinaryReader reader) throws IOException {
223221
this.r_offset = Integer.toUnsignedLong(reader.readNextInt());
224222
this.r_info = Integer.toUnsignedLong(reader.readNextInt());
225223
if (hasAddend) {
226-
r_addend = Integer.toUnsignedLong(reader.readNextInt());
224+
r_addend = reader.readNextInt();
227225
}
228226
}
229227
else {
@@ -307,10 +305,13 @@ public long getRelocationInfo() {
307305
}
308306

309307
/**
310-
* This member specifies a constant addend used to compute
308+
* This member specifies the RELA signed-constant addend used to compute
311309
* the value to be stored into the relocatable field. This
312-
* value will be 0 for REL entries which do not supply an addend.
313-
* @return a constant addend
310+
* value will be 0 for REL entries which do not supply an addend and may
311+
* rely on an implicit addend stored at the relocation offset.
312+
* See {@link #hasAddend()} which is true for RELA / Elf_Rela and false
313+
* for REL / Elf_Rel relocations.
314+
* @return addend as 64-bit signed constant
314315
*/
315316
public long getAddend() {
316317
return r_addend;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/* ###
2+
* IP: GHIDRA
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package ghidra.app.util.bin.format.elf.relocation;
17+
18+
import java.util.*;
19+
20+
import ghidra.app.util.bin.format.elf.*;
21+
import ghidra.program.model.address.Address;
22+
23+
class RISCV_ElfRelocationContext extends ElfRelocationContext {
24+
25+
protected RISCV_ElfRelocationContext(ElfRelocationHandler handler, ElfLoadHelper loadHelper,
26+
Map<ElfSymbol, Address> symbolMap) {
27+
super(handler, loadHelper, symbolMap);
28+
}
29+
30+
/**
31+
* <code>OffsetComparator</code> provides ability to compare a Long ElfSymbol offset value with an
32+
* ElfRelocation object's relocation offset.
33+
*/
34+
private static class OffsetComparator implements Comparator<Object> {
35+
36+
public static final OffsetComparator INSTANCE = new OffsetComparator();
37+
38+
@Override
39+
public int compare(Object o1, Object o2) {
40+
if (o1 instanceof Long) {
41+
return -compare(o2, o1);
42+
}
43+
ElfRelocation rel = (ElfRelocation) o1;
44+
long relOffset = rel.getOffset();
45+
long offset = (Long) o2;
46+
if (relOffset == offset) {
47+
return 0;
48+
}
49+
return Long.compareUnsigned(relOffset, offset);
50+
}
51+
52+
}
53+
54+
/**
55+
* Find the HI20 relocation whose offset matches the value of of the specified symbol.
56+
* @param hi20Symbol ELF symbol which corresponds to HI20 relocation
57+
* @return matching relocation or null if not found
58+
*/
59+
ElfRelocation getHi20Relocation(ElfSymbol hi20Symbol) {
60+
61+
Long symValue = hi20Symbol.getValue();
62+
63+
// Search for first relocation within table whose offset matches the specified hi20Symbol value
64+
ElfRelocation[] relocations = relocationTable.getRelocations();
65+
int relIndex = Arrays.binarySearch(relocations, symValue, OffsetComparator.INSTANCE);
66+
if (relIndex < 0) {
67+
return null; // relocation not found
68+
}
69+
// back-up in the event there is more than one matching relocation offset
70+
while (relIndex > 0 && relocations[relIndex - 1].getOffset() == symValue) {
71+
--relIndex;
72+
}
73+
// look for hi20 relocation
74+
while (relIndex < relocations.length && relocations[relIndex - 1].getOffset() == symValue) {
75+
int type = relocations[relIndex].getType();
76+
if ((type == RISCV_ElfRelocationConstants.R_RISCV_PCREL_HI20) ||
77+
(type == RISCV_ElfRelocationConstants.R_RISCV_GOT_HI20)) {
78+
return relocations[relIndex];
79+
}
80+
}
81+
return null;
82+
}
83+
}

0 commit comments

Comments
 (0)