wasmer_compiler_singlepass/
dwarf.rs

1use gimli::{
2    RunTimeEndian, SectionId,
3    write::{Address, EndianVec, Result, Writer},
4};
5use wasmer_compiler::types::{
6    relocation::{Relocation, RelocationKind, RelocationTarget},
7    section::{CustomSection, CustomSectionProtection, SectionBody},
8};
9use wasmer_types::{LocalFunctionIndex, entity::EntityRef, target::Endianness};
10
11#[derive(Clone, Debug)]
12pub struct WriterRelocate {
13    pub relocs: Vec<Relocation>,
14    writer: EndianVec<RunTimeEndian>,
15}
16
17impl WriterRelocate {
18    pub const FUNCTION_SYMBOL: usize = 0;
19    pub fn new(endianness: Option<Endianness>) -> Self {
20        let endianness = match endianness {
21            Some(Endianness::Little) => RunTimeEndian::Little,
22            Some(Endianness::Big) => RunTimeEndian::Big,
23            // We autodetect it, based on the host
24            None => RunTimeEndian::default(),
25        };
26        WriterRelocate {
27            relocs: Vec::new(),
28            writer: EndianVec::new(endianness),
29        }
30    }
31
32    pub fn into_section(mut self) -> CustomSection {
33        // GCC expects a terminating "empty" length, so write a 0 length at the end of the table.
34        self.writer.write_u32(0).unwrap();
35        let data = self.writer.into_vec();
36        CustomSection {
37            protection: CustomSectionProtection::Read,
38            alignment: None,
39            bytes: SectionBody::new_with_vec(data),
40            relocations: self.relocs,
41        }
42    }
43}
44
45impl Writer for WriterRelocate {
46    type Endian = RunTimeEndian;
47
48    fn endian(&self) -> Self::Endian {
49        self.writer.endian()
50    }
51
52    fn len(&self) -> usize {
53        self.writer.len()
54    }
55
56    fn write(&mut self, bytes: &[u8]) -> Result<()> {
57        self.writer.write(bytes)
58    }
59
60    fn write_at(&mut self, offset: usize, bytes: &[u8]) -> Result<()> {
61        self.writer.write_at(offset, bytes)
62    }
63
64    fn write_address(&mut self, address: Address, size: u8) -> Result<()> {
65        match address {
66            Address::Constant(val) => self.write_udata(val, size),
67            Address::Symbol { symbol, addend } => {
68                // Is a function relocation
69                if symbol == Self::FUNCTION_SYMBOL {
70                    // We use the addend to detect the function index
71                    let function_index = LocalFunctionIndex::new(addend as _);
72                    let reloc_target = RelocationTarget::LocalFunc(function_index);
73                    let offset = self.len() as u32;
74                    let kind = match size {
75                        8 => RelocationKind::Abs8,
76                        _ => unimplemented!("dwarf relocation size not yet supported: {}", size),
77                    };
78                    let addend = 0;
79                    self.relocs.push(Relocation {
80                        kind,
81                        reloc_target,
82                        offset,
83                        addend,
84                    });
85                    self.write_udata(addend as u64, size)
86                } else {
87                    unreachable!("Symbol {} in DWARF not recognized", symbol);
88                }
89            }
90        }
91    }
92
93    fn write_offset(&mut self, _val: usize, _section: SectionId, _size: u8) -> Result<()> {
94        unimplemented!("write_offset not yet implemented");
95    }
96
97    fn write_offset_at(
98        &mut self,
99        _offset: usize,
100        _val: usize,
101        _section: SectionId,
102        _size: u8,
103    ) -> Result<()> {
104        unimplemented!("write_offset_at not yet implemented");
105    }
106}