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