linker_utils/
riscv64.rs

1use crate::bit_misc::BitExtraction;
2use crate::elf::AllowedRange;
3use crate::elf::RelocationKind;
4use crate::elf::RelocationKindInfo;
5use crate::elf::RelocationSize;
6use crate::elf::RiscVInstruction;
7use crate::relaxation::RelocationModifier;
8use crate::utils::and_from_slice;
9use crate::utils::or_from_slice;
10use crate::utils::u32_from_slice;
11use leb128;
12use std::io::Cursor;
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub enum RelaxationKind {
16    /// Leave the instruction alone. Used when we only want to change the kind of relocation used.
17    NoOp,
18
19    /// Replace with nop
20    ReplaceWithNop,
21}
22
23impl RelaxationKind {
24    pub fn apply(self, section_bytes: &mut [u8], offset_in_section: &mut u64, _addend: &mut i64) {
25        let offset = *offset_in_section as usize;
26        match self {
27            RelaxationKind::NoOp => {}
28            RelaxationKind::ReplaceWithNop => {
29                section_bytes[offset..offset + 4].copy_from_slice(&[
30                    0x01, 0x0, // nop
31                    0x01, 0x0, // nop
32                ]);
33            }
34        }
35    }
36
37    #[must_use]
38    pub fn next_modifier(&self) -> RelocationModifier {
39        RelocationModifier::Normal
40    }
41}
42
43#[must_use]
44pub const fn relocation_type_from_raw(r_type: u32) -> Option<RelocationKindInfo> {
45    // The relocation listing following the order defined in the standard:
46    // https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc#relocations
47    let (kind, size, mask, range, alignment) = match r_type {
48        object::elf::R_RISCV_NONE => (
49            RelocationKind::None,
50            RelocationSize::ByteSize(0),
51            None,
52            AllowedRange::no_check(),
53            1,
54        ),
55        object::elf::R_RISCV_32 => (
56            RelocationKind::Absolute,
57            RelocationSize::ByteSize(4),
58            None,
59            AllowedRange::new(-(2i64.pow(31)), 2i64.pow(32)),
60            1,
61        ),
62        object::elf::R_RISCV_64 => (
63            RelocationKind::Absolute,
64            RelocationSize::ByteSize(4),
65            None,
66            AllowedRange::no_check(),
67            1,
68        ),
69        object::elf::R_RISCV_BRANCH => (
70            RelocationKind::Relative,
71            RelocationSize::bit_mask_riscv(0, 32, RiscVInstruction::BType),
72            None,
73            AllowedRange::new(-(2i64.pow(12)), 2i64.pow(13) - 2),
74            1,
75        ),
76        object::elf::R_RISCV_JAL => (
77            RelocationKind::Relative,
78            RelocationSize::bit_mask_riscv(0, 32, RiscVInstruction::JType),
79            None,
80            AllowedRange::new(-(2i64.pow(20)), 2i64.pow(20) - 2),
81            1,
82        ),
83        object::elf::R_RISCV_CALL | object::elf::R_RISCV_CALL_PLT => (
84            RelocationKind::PltRelative,
85            RelocationSize::bit_mask_riscv(0, 64, RiscVInstruction::UiType),
86            None,
87            AllowedRange::new(-(2i64.pow(31)), 2i64.pow(32)),
88            1,
89        ),
90        object::elf::R_RISCV_GOT_HI20 => (
91            RelocationKind::GotRelative,
92            RelocationSize::bit_mask_riscv(0, 32, RiscVInstruction::UType),
93            None,
94            AllowedRange::new(-(2i64.pow(31)), 2i64.pow(32)),
95            1,
96        ),
97        object::elf::R_RISCV_TLS_GOT_HI20 => (
98            RelocationKind::GotTpOff,
99            RelocationSize::bit_mask_riscv(0, 32, RiscVInstruction::UType),
100            None,
101            AllowedRange::new(-(2i64.pow(31)), 2i64.pow(32)),
102            1,
103        ),
104        object::elf::R_RISCV_TLS_GD_HI20 => (
105            RelocationKind::TlsGd,
106            RelocationSize::bit_mask_riscv(0, 32, RiscVInstruction::UType),
107            None,
108            AllowedRange::new(-(2i64.pow(31)), 2i64.pow(32)),
109            1,
110        ),
111        object::elf::R_RISCV_PCREL_HI20 => (
112            RelocationKind::Relative,
113            RelocationSize::bit_mask_riscv(0, 32, RiscVInstruction::UType),
114            None,
115            AllowedRange::new(-(2i64.pow(31)), 2i64.pow(32)),
116            1,
117        ),
118        object::elf::R_RISCV_PCREL_LO12_I => (
119            RelocationKind::RelativeRiscVLow12,
120            RelocationSize::bit_mask_riscv(0, 32, RiscVInstruction::IType),
121            None,
122            AllowedRange::new(-(2i64.pow(31)), 2i64.pow(32)),
123            1,
124        ),
125        object::elf::R_RISCV_PCREL_LO12_S => (
126            RelocationKind::RelativeRiscVLow12,
127            RelocationSize::bit_mask_riscv(0, 32, RiscVInstruction::SType),
128            None,
129            AllowedRange::new(-(2i64.pow(31)), 2i64.pow(32)),
130            1,
131        ),
132        object::elf::R_RISCV_HI20 => (
133            RelocationKind::Absolute,
134            RelocationSize::bit_mask_riscv(0, 32, RiscVInstruction::UType),
135            None,
136            AllowedRange::new(-(2i64.pow(31)), 2i64.pow(32)),
137            1,
138        ),
139        object::elf::R_RISCV_LO12_I => (
140            RelocationKind::Absolute,
141            RelocationSize::bit_mask_riscv(0, 32, RiscVInstruction::IType),
142            None,
143            AllowedRange::new(-(2i64.pow(31)), 2i64.pow(32)),
144            1,
145        ),
146        object::elf::R_RISCV_LO12_S => (
147            RelocationKind::Absolute,
148            RelocationSize::bit_mask_riscv(0, 32, RiscVInstruction::SType),
149            None,
150            AllowedRange::new(-(2i64.pow(31)), 2i64.pow(32)),
151            1,
152        ),
153        object::elf::R_RISCV_TPREL_HI20 => (
154            RelocationKind::TpOff,
155            RelocationSize::bit_mask_riscv(0, 32, RiscVInstruction::UType),
156            None,
157            AllowedRange::new(-(2i64.pow(31)), 2i64.pow(32)),
158            1,
159        ),
160        object::elf::R_RISCV_TPREL_LO12_I => (
161            RelocationKind::TpOff,
162            RelocationSize::bit_mask_riscv(0, 32, RiscVInstruction::IType),
163            None,
164            AllowedRange::new(-(2i64.pow(31)), 2i64.pow(32)),
165            1,
166        ),
167        object::elf::R_RISCV_TPREL_LO12_S => (
168            RelocationKind::TpOff,
169            RelocationSize::bit_mask_riscv(0, 32, RiscVInstruction::SType),
170            None,
171            AllowedRange::new(-(2i64.pow(31)), 2i64.pow(32)),
172            1,
173        ),
174        object::elf::R_RISCV_TPREL_ADD => (
175            RelocationKind::None,
176            RelocationSize::ByteSize(0),
177            None,
178            AllowedRange::no_check(),
179            1,
180        ),
181        object::elf::R_RISCV_ADD8 => (
182            RelocationKind::AbsoluteAddition,
183            RelocationSize::ByteSize(1),
184            None,
185            AllowedRange::no_check(),
186            1,
187        ),
188        object::elf::R_RISCV_ADD16 => (
189            RelocationKind::AbsoluteAddition,
190            RelocationSize::ByteSize(2),
191            None,
192            AllowedRange::no_check(),
193            1,
194        ),
195        object::elf::R_RISCV_ADD32 => (
196            RelocationKind::AbsoluteAddition,
197            RelocationSize::ByteSize(4),
198            None,
199            AllowedRange::no_check(),
200            1,
201        ),
202        object::elf::R_RISCV_ADD64 => (
203            RelocationKind::AbsoluteAddition,
204            RelocationSize::ByteSize(8),
205            None,
206            AllowedRange::no_check(),
207            1,
208        ),
209        object::elf::R_RISCV_SUB8 => (
210            RelocationKind::AbsoluteSubtraction,
211            RelocationSize::ByteSize(1),
212            None,
213            AllowedRange::no_check(),
214            1,
215        ),
216        object::elf::R_RISCV_SUB16 => (
217            RelocationKind::AbsoluteSubtraction,
218            RelocationSize::ByteSize(2),
219            None,
220            AllowedRange::no_check(),
221            1,
222        ),
223        object::elf::R_RISCV_SUB32 => (
224            RelocationKind::AbsoluteSubtraction,
225            RelocationSize::ByteSize(4),
226            None,
227            AllowedRange::no_check(),
228            1,
229        ),
230        object::elf::R_RISCV_SUB64 => (
231            RelocationKind::AbsoluteSubtraction,
232            RelocationSize::ByteSize(8),
233            None,
234            AllowedRange::no_check(),
235            1,
236        ),
237        object::elf::R_RISCV_GOT32_PCREL => (
238            RelocationKind::GotRelative,
239            RelocationSize::ByteSize(4),
240            None,
241            AllowedRange::new(-(2i64.pow(31)), 2i64.pow(32)),
242            1,
243        ),
244        object::elf::R_RISCV_ALIGN => (
245            RelocationKind::Alignment,
246            RelocationSize::ByteSize(0),
247            None,
248            AllowedRange::no_check(),
249            1,
250        ),
251        object::elf::R_RISCV_RVC_BRANCH => (
252            RelocationKind::Relative,
253            RelocationSize::bit_mask_riscv(0, 16, RiscVInstruction::CbType),
254            None,
255            AllowedRange::new(-(2i64.pow(8)), 2i64.pow(9) - 2),
256            1,
257        ),
258        object::elf::R_RISCV_RVC_JUMP => (
259            RelocationKind::Relative,
260            RelocationSize::bit_mask_riscv(0, 16, RiscVInstruction::CjType),
261            None,
262            AllowedRange::new(-(2i64.pow(11)), 2i64.pow(12) - 2),
263            1,
264        ),
265        object::elf::R_RISCV_RELAX => (
266            RelocationKind::None,
267            RelocationSize::ByteSize(0),
268            None,
269            AllowedRange::no_check(),
270            1,
271        ),
272        object::elf::R_RISCV_SUB6 => (
273            RelocationKind::AbsoluteSubtractionWord6,
274            RelocationSize::ByteSize(1),
275            None,
276            AllowedRange::no_check(),
277            1,
278        ),
279        object::elf::R_RISCV_SET6 => (
280            RelocationKind::AbsoluteSetWord6,
281            RelocationSize::ByteSize(1),
282            None,
283            AllowedRange::no_check(),
284            1,
285        ),
286        object::elf::R_RISCV_SET8 => (
287            RelocationKind::AbsoluteSet,
288            RelocationSize::ByteSize(1),
289            None,
290            AllowedRange::no_check(),
291            1,
292        ),
293        object::elf::R_RISCV_SET16 => (
294            RelocationKind::AbsoluteSet,
295            RelocationSize::ByteSize(2),
296            None,
297            AllowedRange::no_check(),
298            1,
299        ),
300        object::elf::R_RISCV_SET32 => (
301            RelocationKind::AbsoluteSet,
302            RelocationSize::ByteSize(4),
303            None,
304            AllowedRange::no_check(),
305            1,
306        ),
307        object::elf::R_RISCV_32_PCREL => (
308            RelocationKind::Relative,
309            RelocationSize::ByteSize(4),
310            None,
311            AllowedRange::new(-(2i64.pow(31)), 2i64.pow(32)),
312            1,
313        ),
314        object::elf::R_RISCV_PLT32 => (
315            RelocationKind::PltRelative,
316            RelocationSize::ByteSize(4),
317            None,
318            AllowedRange::new(-(2i64.pow(31)), 2i64.pow(32)),
319            1,
320        ),
321        // We process the subtraction in the SUB_ULEB128 relocation,
322        // thus we skip the first relocation in the pair.
323        object::elf::R_RISCV_SET_ULEB128 => (
324            RelocationKind::Relative,
325            RelocationSize::ByteSize(0),
326            None,
327            AllowedRange::no_check(),
328            1,
329        ),
330        object::elf::R_RISCV_SUB_ULEB128 => (
331            RelocationKind::PairSubtraction,
332            RelocationSize::bit_mask_riscv(0, 64, RiscVInstruction::Uleb128),
333            None,
334            AllowedRange::no_check(),
335            1,
336        ),
337        // TODO: #712: support TLSDESC once glibc supports the feature
338        object::elf::R_RISCV_TLSDESC_HI20 => return None,
339        object::elf::R_RISCV_TLSDESC_LOAD_LO12 => return None,
340        object::elf::R_RISCV_TLSDESC_ADD_LO12 => return None,
341        object::elf::R_RISCV_TLSDESC_CALL => return None,
342        _ => return None,
343    };
344
345    Some(RelocationKindInfo {
346        kind,
347        size,
348        mask,
349        range,
350        alignment,
351    })
352}
353
354const UTYPE_IMMEDIATE_MASK: u32 = 0b0000_0000_0000_0000_0000_1111_1111_1111;
355const ITYPE_IMMEDIATE_MASK: u32 = 0b0000_0000_0000_1111_1111_1111_1111_1111;
356const STYPE_IMMEDIATE_MASK: u32 = 0b0000_0001_1111_1111_1111_0000_0111_1111;
357const BTYPE_IMMEDIATE_MASK: u32 = 0b0000_0001_1111_1111_1111_0000_0111_1111;
358const JTYPE_IMMEDIATE_MASK: u32 = 0b0000_0000_0000_0000_0000_1111_1111_1111;
359
360const CBTYPE_IMMEDIATE_MASK: u16 = 0b1110_0011_1000_0011;
361const CJTYPE_IMMEDIATE_MASK: u16 = 0b1110_0000_0000_0011;
362
363impl RiscVInstruction {
364    // Encode computed relocation value and store it based on the encoding of an instruction.
365    // A handy page where one can easily find instruction encoding:
366    // https://msyksphinz-self.github.io/riscv-isadoc/html/index.html.
367
368    // During the build of the static libc.a, there are various places where the immediate operand
369    // of an instruction is already filled up. Thus, we zero the bits before a relocation value is applied.
370    pub fn write_to_value(self, extracted_value: u64, _negative: bool, dest: &mut [u8]) {
371        match self {
372            RiscVInstruction::UiType => {
373                RiscVInstruction::UType.write_to_value(extracted_value, _negative, &mut dest[..4]);
374                RiscVInstruction::IType.write_to_value(extracted_value, _negative, &mut dest[4..]);
375            }
376            RiscVInstruction::UType => {
377                // A final address calculation is represented as addition of HI20 and LO12, where
378                // we must prevent add 0x800 in order to not make HI20 a huge negative if the final
379                // value is a small negative value.
380                // For instance, -10i32 (0xfffffff6) should become 0x0 (HI20) and 0xff6 (LO12).
381                let mask = (extracted_value.wrapping_add(0x800).extract_bits(12..32) as u32) << 12;
382                and_from_slice(dest, UTYPE_IMMEDIATE_MASK.to_le_bytes().as_slice());
383                or_from_slice(dest, &mask.to_le_bytes());
384            }
385            RiscVInstruction::IType => {
386                let mask = extracted_value << 20;
387                and_from_slice(dest, ITYPE_IMMEDIATE_MASK.to_le_bytes().as_slice());
388                or_from_slice(dest, &(mask as u32).to_le_bytes());
389            }
390            RiscVInstruction::SType => {
391                let mut mask = extracted_value.extract_bits(0..5) << 7;
392                mask |= extracted_value.extract_bits(5..12) << 25;
393                and_from_slice(dest, STYPE_IMMEDIATE_MASK.to_le_bytes().as_slice());
394                or_from_slice(dest, &(mask as u32).to_le_bytes());
395            }
396            RiscVInstruction::BType => {
397                let mut mask = extracted_value.extract_bit(11) << 7;
398                mask |= extracted_value.extract_bits(1..5) << 8;
399                mask |= extracted_value.extract_bits(5..11) << 25;
400                mask |= extracted_value.extract_bit(12) << 31;
401                and_from_slice(dest, BTYPE_IMMEDIATE_MASK.to_le_bytes().as_slice());
402                or_from_slice(dest, &(mask as u32).to_le_bytes());
403            }
404            RiscVInstruction::JType => {
405                let mut mask = extracted_value.extract_bits(12..20) << 12;
406                mask |= extracted_value.extract_bit(11) << 20;
407                mask |= extracted_value.extract_bits(1..11) << 21;
408                mask |= extracted_value.extract_bit(20) << 31;
409                and_from_slice(dest, JTYPE_IMMEDIATE_MASK.to_le_bytes().as_slice());
410                or_from_slice(dest, &(mask as u32).to_le_bytes());
411            }
412            RiscVInstruction::CbType => {
413                let mut mask = extracted_value.extract_bit(5) << 2;
414                mask |= extracted_value.extract_bits(1..3) << 3;
415                mask |= extracted_value.extract_bits(6..8) << 5;
416                // rs1' register takes 3 bits here
417                mask |= extracted_value.extract_bits(3..5) << 10;
418                mask |= extracted_value.extract_bit(8) << 12;
419                // The compressed instruction only takes 2 bytes.
420                and_from_slice(dest, CBTYPE_IMMEDIATE_MASK.to_le_bytes().as_slice());
421                or_from_slice(dest, &mask.to_le_bytes()[..2]);
422            }
423            RiscVInstruction::CjType => {
424                let mut mask = extracted_value.extract_bit(5) << 2;
425                mask |= extracted_value.extract_bits(1..4) << 3;
426                mask |= extracted_value.extract_bit(7) << 6;
427                mask |= extracted_value.extract_bit(6) << 7;
428                mask |= extracted_value.extract_bit(10) << 8;
429                mask |= extracted_value.extract_bits(8..10) << 9;
430                mask |= extracted_value.extract_bit(4) << 11;
431                mask |= extracted_value.extract_bit(11) << 12;
432                // The compressed instruction only takes 2 bytes.
433                and_from_slice(dest, CJTYPE_IMMEDIATE_MASK.to_le_bytes().as_slice());
434                or_from_slice(dest, &mask.to_le_bytes()[..2]);
435            }
436            RiscVInstruction::Uleb128 => {
437                // u64 always fits in 10 bytes in the ULEB format: 64 / 7 = 9.14
438                let mut writer = Cursor::new(vec![0u8; 10]);
439                let n = leb128::write::unsigned(&mut writer, extracted_value)
440                    .expect("Must fit into the buffer");
441                dest[..n].copy_from_slice(&writer.into_inner()[..n]);
442            }
443        };
444    }
445
446    /// The inverse of `write_to_value`. Returns `(extracted_value, negative)`. Supplied `bytes`
447    /// must be at least 4 bytes, otherwise we panic.
448    #[must_use]
449    pub fn read_value(self, bytes: &[u8]) -> (u64, bool) {
450        match self {
451            RiscVInstruction::UiType => {
452                let (hi, _) = RiscVInstruction::UType.read_value(&bytes[..4]);
453                let (lo, _) = RiscVInstruction::IType.read_value(&bytes[4..]);
454                (hi << 12 | lo, false)
455            }
456            RiscVInstruction::UType => {
457                let value = u32_from_slice(bytes);
458                let imm = (value >> 12) & 0xfffff;
459                let adjusted = ((imm as i32) << 12) >> 12;
460                ((adjusted as u64).wrapping_sub(0x800), false)
461            }
462            RiscVInstruction::IType => {
463                let value = u32_from_slice(bytes);
464                let imm = (value >> 20) & 0xfff;
465                let sign_extended = ((imm as i32) << 20) >> 20;
466                (sign_extended as u64, sign_extended < 0)
467            }
468            RiscVInstruction::SType => {
469                let value = u32_from_slice(bytes);
470                let imm_low = (value >> 7) & 0x1f;
471                let imm_high = (value >> 25) & 0x7f;
472                let imm = (imm_high << 5) | imm_low;
473                let sign_extended = ((imm as i32) << 20) >> 20;
474                (sign_extended as u64, sign_extended < 0)
475            }
476            RiscVInstruction::BType => {
477                let value = u32_from_slice(bytes);
478                let imm11 = (value >> 7) & 0x1;
479                let imm1_4 = (value >> 8) & 0xf;
480                let imm5_10 = (value >> 25) & 0x3f;
481                let imm12 = (value >> 31) & 0x1;
482
483                let imm = (imm12 << 12) | (imm11 << 11) | (imm5_10 << 5) | (imm1_4 << 1);
484                let sign_extended = ((imm as i32) << 19) >> 19;
485                (sign_extended as u64, sign_extended < 0)
486            }
487            RiscVInstruction::JType => {
488                let value = u32_from_slice(bytes);
489                let imm12_19 = (value >> 12) & 0xff;
490                let imm11 = (value >> 20) & 0x1;
491                let imm1_10 = (value >> 21) & 0x3ff;
492                let imm20 = (value >> 31) & 0x1;
493
494                let imm = (imm20 << 20) | (imm12_19 << 12) | (imm11 << 11) | (imm1_10 << 1);
495                let sign_extended = ((imm as i32) << 11) >> 11;
496                (sign_extended as u64, sign_extended < 0)
497            }
498            RiscVInstruction::CbType => {
499                let value = u16::from_le_bytes([bytes[0], bytes[1]]);
500                let imm5 = (value >> 2) & 0x1;
501                let imm1_2 = (value >> 3) & 0x3;
502                let imm6_7 = (value >> 5) & 0x3;
503                let imm3_4 = (value >> 10) & 0x3;
504                let imm8 = (value >> 12) & 0x1;
505
506                let imm = (imm8 << 8) | (imm6_7 << 6) | (imm5 << 5) | (imm3_4 << 3) | (imm1_2 << 1);
507                let sign_extended = (i32::from(imm) << 23) >> 23;
508                (sign_extended as u64, sign_extended < 0)
509            }
510            RiscVInstruction::CjType => {
511                let value = u16::from_le_bytes([bytes[0], bytes[1]]);
512                let imm5 = (value >> 2) & 0x1;
513                let imm1_3 = (value >> 3) & 0x7;
514                let imm7 = (value >> 6) & 0x1;
515                let imm6 = (value >> 7) & 0x1;
516                let imm10 = (value >> 8) & 0x1;
517                let imm8_9 = (value >> 9) & 0x3;
518                let imm4 = (value >> 11) & 0x1;
519                let imm11 = (value >> 12) & 0x1;
520
521                let imm = (imm11 << 11)
522                    | (imm10 << 10)
523                    | (imm8_9 << 8)
524                    | (imm7 << 7)
525                    | (imm6 << 6)
526                    | (imm5 << 5)
527                    | (imm4 << 4)
528                    | (imm1_3 << 1);
529                let sign_extended = (i32::from(imm) << 20) >> 20;
530                (sign_extended as u64, sign_extended < 0)
531            }
532            RiscVInstruction::Uleb128 => {
533                let mut reader = Cursor::new(bytes);
534                match leb128::read::unsigned(&mut reader) {
535                    Ok(value) => (value, false),
536                    Err(_) => panic!("Failed to read ULEB128 value"),
537                }
538            }
539        }
540    }
541}
542
543#[test]
544fn test_riscv_insn_immediate_mask() {
545    for (mask, insn) in &[
546        (UTYPE_IMMEDIATE_MASK, RiscVInstruction::UType),
547        (ITYPE_IMMEDIATE_MASK, RiscVInstruction::IType),
548        (STYPE_IMMEDIATE_MASK, RiscVInstruction::SType),
549        (BTYPE_IMMEDIATE_MASK, RiscVInstruction::BType),
550        (JTYPE_IMMEDIATE_MASK, RiscVInstruction::JType),
551    ] {
552        let mut dest = [0u8; 4];
553        let value = if matches!(insn, RiscVInstruction::UType) {
554            u64::MAX.wrapping_sub(0x800)
555        } else {
556            u64::MAX
557        };
558        insn.write_to_value(value, false, &mut dest);
559        assert_eq!(!mask, u32::from_le_bytes(dest));
560    }
561}
562
563#[test]
564fn test_riscv_insn_rvcimmediate_mask() {
565    for (mask, insn) in &[
566        (CBTYPE_IMMEDIATE_MASK, RiscVInstruction::CbType),
567        (CJTYPE_IMMEDIATE_MASK, RiscVInstruction::CjType),
568    ] {
569        let mut dest = [0u8; 2];
570        insn.write_to_value(u64::from(u16::MAX), false, &mut dest);
571        assert_eq!(!mask, u16::from_le_bytes(dest));
572    }
573}