@@ -829,6 +829,9 @@ pub(crate) struct AddressIndex<'data> {
829
829
tls_segment_size : u64 ,
830
830
load_offset : u64 ,
831
831
832
+ /// GOT addresses for each JMPREL relocation by their index.
833
+ jmprel_got_addresses : Vec < u64 > ,
834
+
832
835
/// The address of the start of the .got section.
833
836
got_base_address : Option < u64 > ,
834
837
@@ -887,6 +890,7 @@ impl<'data> AddressIndex<'data> {
887
890
verneed : Default :: default ( ) ,
888
891
load_offset : decide_load_offset ( object) ,
889
892
dynamic_symbol_names : Default :: default ( ) ,
893
+ jmprel_got_addresses : Vec :: new ( ) ,
890
894
} ;
891
895
892
896
if let Err ( error) = info. build_indexes ( object) {
@@ -1084,29 +1088,38 @@ impl<'data> AddressIndex<'data> {
1084
1088
if let Ok ( Some ( ( relocations, _) ) ) =
1085
1089
elf_section_header. rela ( LittleEndian , elf_file. data ( ) )
1086
1090
{
1091
+ let mut jmprel_got_addresses = ( Some ( elf_section_header. sh_addr ( LittleEndian ) )
1092
+ == self . jmprel_address )
1093
+ . then ( || Vec :: with_capacity ( relocations. len ( ) ) ) ;
1087
1094
for rel in relocations {
1088
- self . index_dynamic_relocation ( rel, elf_file) ;
1095
+ let address = self . index_dynamic_relocation ( rel, elf_file) ;
1096
+ if let Some ( j) = jmprel_got_addresses. as_mut ( ) {
1097
+ j. push ( address) ;
1098
+ }
1099
+ }
1100
+ if let Some ( j) = jmprel_got_addresses {
1101
+ self . jmprel_got_addresses = j;
1089
1102
}
1090
1103
}
1091
1104
}
1092
1105
}
1093
1106
}
1094
1107
1095
- fn index_dynamic_relocation ( & mut self , rel : & Rela64 , elf_file : & ElfFile64 ) {
1108
+ fn index_dynamic_relocation ( & mut self , rel : & Rela64 , elf_file : & ElfFile64 ) -> u64 {
1096
1109
let e = LittleEndian ;
1097
1110
let r_type = rel. r_type ( e, false ) ;
1098
1111
let address = self . load_offset + rel. r_offset ( e) ;
1099
1112
let symbol_index = rel. r_sym ( e, false ) ;
1100
1113
if symbol_index != 0 {
1101
1114
let Some ( symbol_name) = self . dynamic_symbol_names . get ( symbol_index as usize ) else {
1102
- return ;
1115
+ return address ;
1103
1116
} ;
1104
1117
let basic = match r_type {
1105
1118
object:: elf:: R_X86_64_COPY => BasicResolution :: Copy ( * symbol_name) ,
1106
1119
_ => BasicResolution :: Dynamic ( * symbol_name) ,
1107
1120
} ;
1108
1121
self . add_resolution ( address, AddressResolution :: Basic ( basic) ) ;
1109
- return ;
1122
+ return address ;
1110
1123
}
1111
1124
match r_type {
1112
1125
object:: elf:: R_X86_64_DTPMOD64 => {
@@ -1144,6 +1157,7 @@ impl<'data> AddressIndex<'data> {
1144
1157
}
1145
1158
_ => { }
1146
1159
}
1160
+ address
1147
1161
}
1148
1162
1149
1163
fn index_plt_sections ( & mut self , elf_file : & ElfFile64 < ' data > ) -> Result {
@@ -1176,7 +1190,6 @@ impl<'data> AddressIndex<'data> {
1176
1190
if let Some ( got_address) = PltEntry :: decode ( chunk, plt_base, plt_offset)
1177
1191
. map ( |entry| self . got_address ( entry) )
1178
1192
. transpose ( ) ?
1179
- . map ( |o| self . load_offset + o)
1180
1193
{
1181
1194
for res in self . resolve ( got_address) {
1182
1195
if let AddressResolution :: Basic ( got_resolution) = res {
@@ -1234,11 +1247,17 @@ impl<'data> AddressIndex<'data> {
1234
1247
1235
1248
fn got_address ( & self , plt_entry : PltEntry ) -> Result < u64 > {
1236
1249
match plt_entry {
1237
- PltEntry :: DerefJmp ( address) => Ok ( address) ,
1238
- PltEntry :: GotIndex ( got_index) => Ok ( self
1239
- . got_plt_address
1240
- . context ( "Index-based PLT entry with no DT_PLTGOT" ) ?
1241
- + u64:: from ( got_index) * 8 ) ,
1250
+ PltEntry :: DerefJmp ( address) => Ok ( address + self . load_offset ) ,
1251
+ PltEntry :: JumpSlot ( index) => self
1252
+ . jmprel_got_addresses
1253
+ . get ( index as usize )
1254
+ . copied ( )
1255
+ . with_context ( || {
1256
+ format ! (
1257
+ "Invalid jump slot index {index} out of {}" ,
1258
+ self . jmprel_got_addresses. len( )
1259
+ )
1260
+ } ) ,
1242
1261
}
1243
1262
}
1244
1263
@@ -1475,9 +1494,8 @@ enum PltEntry {
1475
1494
/// PLT entry then jumped to.
1476
1495
DerefJmp ( u64 ) ,
1477
1496
1478
- /// The parameter is an index into the GOT. This is used by PLT entries that are going to be
1479
- /// lazily evaluated.
1480
- GotIndex ( u32 ) ,
1497
+ /// The parameter is an index into .rela.plt.
1498
+ JumpSlot ( u32 ) ,
1481
1499
}
1482
1500
1483
1501
impl PltEntry {
@@ -1539,7 +1557,7 @@ impl PltEntry {
1539
1557
// instructions, so that we support these variants.
1540
1558
if plt_entry[ ..5 ] == PLT_ENTRY_TEMPLATE [ ..5 ] {
1541
1559
let index = u32:: from_le_bytes ( * plt_entry[ 5 ..] . first_chunk :: < 4 > ( ) . unwrap ( ) ) ;
1542
- return Some ( PltEntry :: GotIndex ( index) ) ;
1560
+ return Some ( PltEntry :: JumpSlot ( index) ) ;
1543
1561
}
1544
1562
}
1545
1563
0 commit comments