Skip to content

Commit 72fe71c

Browse files
feat: implement R_X86_64_CODE_* relocations with relaxations (#1632)
closes #1299 This PR adds support for the `R_X86_64_CODE_*` relocations, with relaxations wherever possible. --------- Signed-off-by: vishruth-thimmaiah <vishruththimmaiah@gmail.com>
1 parent fbb2d5f commit 72fe71c

10 files changed

Lines changed: 234 additions & 47 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ libloading = "0.9.0"
6161
memchr = "2.6.0"
6262
memmap2 = "0.9.0"
6363
mimalloc = { version = "0.1", default-features = false }
64-
object = { version = "0.38.1", default-features = false, features = [
64+
object = { git = "https://github.com/gimli-rs/object", rev = "ae958b9f2c8a3a56fe19bb4b380144a32eebb770", default-features = false, features = [
6565
"elf",
6666
"read_core",
6767
"std",

libwild/src/elf_x86_64.rs

Lines changed: 64 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -161,10 +161,11 @@ impl<'data> crate::platform::Platform<'data> for ElfX86_64 {
161161
let offset = offset_in_section as usize;
162162

163163
match relocation_kind {
164-
object::elf::R_X86_64_REX_GOTPCRELX => {
165-
if offset < 3 {
166-
return None;
167-
}
164+
object::elf::R_X86_64_REX_GOTPCRELX | object::elf::R_X86_64_CODE_4_GOTPCRELX
165+
if ((relocation_kind == object::elf::R_X86_64_CODE_4_GOTPCRELX
166+
&& (offset >= 4 && section_bytes[offset - 4] == 0xd5))
167+
|| offset >= 3) =>
168+
{
168169
let b1 = section_bytes[offset - 2];
169170
let rex = section_bytes[offset - 3];
170171

@@ -174,27 +175,32 @@ impl<'data> crate::platform::Platform<'data> for ElfX86_64 {
174175
}
175176

176177
if is_absolute || is_absolute_address {
178+
let inst_offset = if relocation_kind == object::elf::R_X86_64_REX_GOTPCRELX {
179+
3
180+
} else {
181+
4
182+
};
177183
match b1 {
178184
// mov *x(%rip), reg
179185
0x8b => {
180186
return Some(Relaxation {
181-
kind: RelaxationKind::RexMovIndirectToAbsolute,
187+
kind: RelaxationKind::RexMovIndirectToAbsolute(inst_offset),
182188
rel_info: rel_info_from_type!(object::elf::R_X86_64_32),
183189
mandatory: output_kind.is_static_executable(),
184190
});
185191
}
186192
// sub *x(%rip), reg
187193
0x2b => {
188194
return Some(Relaxation {
189-
kind: RelaxationKind::RexSubIndirectToAbsolute,
195+
kind: RelaxationKind::RexSubIndirectToAbsolute(inst_offset),
190196
rel_info: rel_info_from_type!(object::elf::R_X86_64_32),
191197
mandatory: output_kind.is_static_executable(),
192198
});
193199
}
194200
// cmp *x(%rip), reg
195201
0x3b => {
196202
return Some(Relaxation {
197-
kind: RelaxationKind::RexCmpIndirectToAbsolute,
203+
kind: RelaxationKind::RexCmpIndirectToAbsolute(inst_offset),
198204
rel_info: rel_info_from_type!(object::elf::R_X86_64_32),
199205
mandatory: output_kind.is_static_executable(),
200206
});
@@ -272,12 +278,48 @@ impl<'data> crate::platform::Platform<'data> for ElfX86_64 {
272278
}
273279
return None;
274280
}
275-
object::elf::R_X86_64_GOTTPOFF if output_kind.is_executable() && !interposable => {
281+
object::elf::R_X86_64_GOTTPOFF | object::elf::R_X86_64_CODE_4_GOTTPOFF
282+
if output_kind.is_executable()
283+
&& !interposable
284+
&& ((relocation_kind == object::elf::R_X86_64_CODE_4_GOTTPOFF
285+
&& (offset >= 4 && section_bytes[offset - 4] == 0xd5))
286+
|| offset >= 3) =>
287+
{
288+
let inst_offset = if relocation_kind == object::elf::R_X86_64_GOTTPOFF {
289+
3
290+
} else {
291+
4
292+
};
293+
276294
match section_bytes.get(offset - 3..offset - 1)? {
277295
// mov *x(%rip), reg
278296
[0x48 | 0x4c, 0x8b] => {
279297
return Some(Relaxation {
280-
kind: RelaxationKind::RexMovIndirectToAbsolute,
298+
kind: RelaxationKind::RexMovIndirectToAbsolute(inst_offset),
299+
rel_info: rel_info_from_type!(object::elf::R_X86_64_TPOFF32),
300+
mandatory: false,
301+
});
302+
}
303+
// add *x(%rip), reg1, reg2
304+
[0x48 | 0x4c, 0x03] => {
305+
return Some(Relaxation {
306+
kind: RelaxationKind::RexAddIndirectToAbsolute(inst_offset),
307+
rel_info: rel_info_from_type!(object::elf::R_X86_64_TPOFF32),
308+
mandatory: false,
309+
});
310+
}
311+
_ => {}
312+
}
313+
}
314+
object::elf::R_X86_64_CODE_6_GOTTPOFF
315+
if output_kind.is_executable() && !interposable && offset >= 6 =>
316+
{
317+
match section_bytes.get(offset - 6..offset - 1)? {
318+
[0x62, l5, l4, l3, 0x1 | 0x3]
319+
if (l5 & 0x47) == 0x44 && l4 & 0x87 == 0x84 && l3 & 0x14 != 0 =>
320+
{
321+
return Some(Relaxation {
322+
kind: RelaxationKind::RexAddIndirectToAbsolute(6),
281323
rel_info: rel_info_from_type!(object::elf::R_X86_64_TPOFF32),
282324
mandatory: false,
283325
});
@@ -358,14 +400,25 @@ impl<'data> crate::platform::Platform<'data> for ElfX86_64 {
358400
}
359401
}
360402
object::elf::R_X86_64_GOTPC32_TLSDESC
361-
if !interposable && output_kind.is_executable() =>
403+
| object::elf::R_X86_64_CODE_4_GOTPC32_TLSDESC
404+
if !interposable
405+
&& output_kind.is_executable()
406+
&& ((relocation_kind == object::elf::R_X86_64_CODE_4_GOTPC32_TLSDESC
407+
&& (offset >= 4 && section_bytes[offset - 4] == 0xd5))
408+
|| offset >= 3) =>
362409
{
363410
// We require that the instruction that this relocation applies to is a LEA
364411
// instruction.
365412
let bytes = section_bytes.get(offset - 3..offset - 1);
366413
if bytes == Some(&[0x48, 0x8d]) || bytes == Some(&[0x4c, 0x8d]) {
367414
return Some(Relaxation {
368-
kind: RelaxationKind::TlsDescToLocalExec,
415+
kind: RelaxationKind::TlsDescToLocalExec(
416+
if relocation_kind == object::elf::R_X86_64_GOTPC32_TLSDESC {
417+
3
418+
} else {
419+
4
420+
},
421+
),
369422
rel_info: rel_info_from_type!(object::elf::R_X86_64_TPOFF32),
370423
mandatory: output_kind.is_static_executable(),
371424
});

linker-diff/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ impl Config {
207207
"section.eh_frame.flags",
208208
// TLSDESC relaxations aren't yet implemented.
209209
"rel.match_failed.R_X86_64_GOTPC32_TLSDESC",
210+
"rel.match_failed.R_X86_64_CODE_4_GOTPC32_TLSDESC",
210211
"rel.missing-opt.R_X86_64_TLSDESC_CALL.SkipTlsDescCall.*",
211212
// Wild eliminates GOTPCRELX in statically linked executables even for undefined
212213
// symbols, whereas other linkers don't. This is a valid optimisation that other

linker-diff/src/x86_64.rs

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ impl Arch for X86_64 {
2626

2727
type RawInstruction = iced_x86::Instruction;
2828

29-
const MAX_RELAX_MODIFY_BEFORE: u64 = 4;
29+
const MAX_RELAX_MODIFY_BEFORE: u64 = 6;
3030
const MAX_RELAX_MODIFY_AFTER: u64 = 19;
3131

3232
fn next_relocation_modifier(
@@ -39,9 +39,11 @@ impl Arch for X86_64 {
3939
match relaxation.relaxation_kind {
4040
Self::RelaxationKind::MovIndirectToLea => RelaxationByteRange::new(2, 6),
4141
Self::RelaxationKind::MovIndirectToAbsolute => RelaxationByteRange::new(2, 6),
42-
Self::RelaxationKind::RexMovIndirectToAbsolute => RelaxationByteRange::new(3, 7),
43-
Self::RelaxationKind::RexSubIndirectToAbsolute => RelaxationByteRange::new(3, 7),
44-
Self::RelaxationKind::RexCmpIndirectToAbsolute => RelaxationByteRange::new(3, 7),
42+
Self::RelaxationKind::RexMovIndirectToAbsolute(_) => RelaxationByteRange::new(3, 7),
43+
Self::RelaxationKind::RexAddIndirectToAbsolute(6) => RelaxationByteRange::new(6, 10),
44+
Self::RelaxationKind::RexAddIndirectToAbsolute(_) => RelaxationByteRange::new(3, 7),
45+
Self::RelaxationKind::RexSubIndirectToAbsolute(_) => RelaxationByteRange::new(3, 7),
46+
Self::RelaxationKind::RexCmpIndirectToAbsolute(_) => RelaxationByteRange::new(3, 7),
4547
Self::RelaxationKind::CallIndirectToRelative => RelaxationByteRange::new(2, 6),
4648
Self::RelaxationKind::JmpIndirectToRelative => RelaxationByteRange::new(2, 6),
4749
Self::RelaxationKind::TlsGdToLocalExec => RelaxationByteRange::new(4, 16),
@@ -51,7 +53,7 @@ impl Arch for X86_64 {
5153
Self::RelaxationKind::TlsLdToLocalExecNoPlt => RelaxationByteRange::new(3, 13),
5254
Self::RelaxationKind::TlsLdToLocalExec64 => RelaxationByteRange::new(3, 22),
5355
Self::RelaxationKind::SkipTlsDescCall => RelaxationByteRange::new(0, 2),
54-
Self::RelaxationKind::TlsDescToLocalExec => RelaxationByteRange::new(3, 7),
56+
Self::RelaxationKind::TlsDescToLocalExec(_) => RelaxationByteRange::new(3, 7),
5557
Self::RelaxationKind::TlsDescToInitialExec => RelaxationByteRange::new(3, 7),
5658
Self::RelaxationKind::NoOp => match relaxation.new_r_type.0 {
5759
// TLSDESC_CALL is a relocation that does nothing unless it's optimised away. To
@@ -97,22 +99,36 @@ impl Arch for X86_64 {
9799
match (section_kind, r_type.0) {
98100
(SectionKind::Text, object::elf::R_X86_64_REX_GOTPCRELX) => {
99101
relax(
100-
Self::RelaxationKind::RexMovIndirectToAbsolute,
102+
Self::RelaxationKind::RexMovIndirectToAbsolute(3),
101103
object::elf::R_X86_64_32,
102104
);
103105
relax(
104-
Self::RelaxationKind::RexSubIndirectToAbsolute,
106+
Self::RelaxationKind::RexSubIndirectToAbsolute(3),
105107
object::elf::R_X86_64_32,
106108
);
107109
relax(
108-
Self::RelaxationKind::RexCmpIndirectToAbsolute,
110+
Self::RelaxationKind::RexCmpIndirectToAbsolute(3),
109111
object::elf::R_X86_64_32,
110112
);
111113
relax(
112114
Self::RelaxationKind::MovIndirectToLea,
113115
object::elf::R_X86_64_PC32,
114116
);
115117
}
118+
(SectionKind::Text, object::elf::R_X86_64_CODE_4_GOTPCRELX) => {
119+
relax(
120+
Self::RelaxationKind::RexMovIndirectToAbsolute(4),
121+
object::elf::R_X86_64_32,
122+
);
123+
relax(
124+
Self::RelaxationKind::RexSubIndirectToAbsolute(4),
125+
object::elf::R_X86_64_32,
126+
);
127+
relax(
128+
Self::RelaxationKind::RexCmpIndirectToAbsolute(4),
129+
object::elf::R_X86_64_32,
130+
);
131+
}
116132
(SectionKind::Text, object::elf::R_X86_64_GOTPCRELX) => {
117133
relax(
118134
Self::RelaxationKind::MovIndirectToAbsolute,
@@ -139,7 +155,23 @@ impl Arch for X86_64 {
139155
}
140156
(SectionKind::Text, object::elf::R_X86_64_GOTTPOFF) => {
141157
relax(
142-
Self::RelaxationKind::RexMovIndirectToAbsolute,
158+
Self::RelaxationKind::RexMovIndirectToAbsolute(3),
159+
object::elf::R_X86_64_TPOFF32,
160+
);
161+
}
162+
(SectionKind::Text, object::elf::R_X86_64_CODE_4_GOTTPOFF) => {
163+
relax(
164+
Self::RelaxationKind::RexMovIndirectToAbsolute(4),
165+
object::elf::R_X86_64_TPOFF32,
166+
);
167+
relax(
168+
Self::RelaxationKind::RexAddIndirectToAbsolute(4),
169+
object::elf::R_X86_64_TPOFF32,
170+
);
171+
}
172+
(SectionKind::Text, object::elf::R_X86_64_CODE_6_GOTTPOFF) => {
173+
relax(
174+
Self::RelaxationKind::RexAddIndirectToAbsolute(6),
143175
object::elf::R_X86_64_TPOFF32,
144176
);
145177
}

linker-utils/src/elf.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,15 @@ pub fn x86_64_rel_type_to_string(r_type: u32) -> Cow<'static, str> {
215215
R_X86_64_RELATIVE64,
216216
R_X86_64_GOTPCRELX,
217217
R_X86_64_REX_GOTPCRELX,
218+
R_X86_64_CODE_4_GOTPCRELX,
219+
R_X86_64_CODE_4_GOTTPOFF,
220+
R_X86_64_CODE_4_GOTPC32_TLSDESC,
221+
R_X86_64_CODE_5_GOTPCRELX,
222+
R_X86_64_CODE_5_GOTTPOFF,
223+
R_X86_64_CODE_5_GOTPC32_TLSDESC,
224+
R_X86_64_CODE_6_GOTPCRELX,
225+
R_X86_64_CODE_6_GOTTPOFF,
226+
R_X86_64_CODE_6_GOTPC32_TLSDESC,
218227
] {
219228
Cow::Borrowed(name)
220229
} else {

0 commit comments

Comments
 (0)