wasmer_compiler_cranelift/
dwarf.rs

1use gimli::write::{Address, EndianVec, Result, Writer};
2use gimli::{RunTimeEndian, SectionId, constants};
3use std::collections::HashMap;
4use wasmer_compiler::types::{
5    relocation::{Relocation, RelocationKind, RelocationTarget},
6    section::{CustomSection, CustomSectionProtection, SectionBody},
7};
8use wasmer_types::{LibCall, LocalFunctionIndex, entity::EntityRef, target::Endianness};
9
10#[derive(Clone, Debug)]
11pub struct WriterRelocate {
12    pub relocs: Vec<Relocation>,
13    writer: EndianVec<RunTimeEndian>,
14    lsda_symbols: HashMap<usize, (RelocationTarget, u32)>,
15}
16
17impl WriterRelocate {
18    pub const FUNCTION_SYMBOL: usize = 0;
19    pub const PERSONALITY_SYMBOL: usize = 1;
20    pub const LSDA_SYMBOL_BASE: usize = 2;
21
22    pub fn new(endianness: Option<Endianness>) -> Self {
23        let endianness = match endianness {
24            Some(Endianness::Little) => RunTimeEndian::Little,
25            Some(Endianness::Big) => RunTimeEndian::Big,
26            // We autodetect it, based on the host
27            None => RunTimeEndian::default(),
28        };
29        Self {
30            relocs: Vec::new(),
31            writer: EndianVec::new(endianness),
32            lsda_symbols: HashMap::new(),
33        }
34    }
35
36    pub fn register_lsda_symbol(&mut self, symbol: usize, target: RelocationTarget, offset: u32) {
37        self.lsda_symbols.insert(symbol, (target, offset));
38    }
39
40    pub fn lsda_symbol(func_index: LocalFunctionIndex) -> usize {
41        Self::LSDA_SYMBOL_BASE + func_index.index()
42    }
43
44    pub fn into_section(mut self) -> CustomSection {
45        // GCC expects a terminating "empty" length, so write a 0 length at the end of the table.
46        self.writer.write_u32(0).unwrap();
47        let data = self.writer.into_vec();
48        CustomSection {
49            protection: CustomSectionProtection::Read,
50            alignment: None,
51            bytes: SectionBody::new_with_vec(data),
52            relocations: self.relocs,
53        }
54    }
55}
56
57impl Writer for WriterRelocate {
58    type Endian = RunTimeEndian;
59
60    fn endian(&self) -> Self::Endian {
61        self.writer.endian()
62    }
63
64    fn len(&self) -> usize {
65        self.writer.len()
66    }
67
68    fn write(&mut self, bytes: &[u8]) -> Result<()> {
69        self.writer.write(bytes)
70    }
71
72    fn write_at(&mut self, offset: usize, bytes: &[u8]) -> Result<()> {
73        self.writer.write_at(offset, bytes)
74    }
75
76    fn write_address(&mut self, address: Address, size: u8) -> Result<()> {
77        match address {
78            Address::Constant(val) => self.write_udata(val, size),
79            Address::Symbol { symbol, addend } => {
80                // Is a function relocation
81                if symbol == Self::FUNCTION_SYMBOL {
82                    // We use the addend to detect the function index
83                    let function_index = LocalFunctionIndex::new(addend as _);
84                    let reloc_target = RelocationTarget::LocalFunc(function_index);
85                    let offset = self.len() as u32;
86                    let kind = match size {
87                        8 => RelocationKind::Abs8,
88                        _ => unimplemented!("dwarf relocation size not yet supported: {}", size),
89                    };
90                    let addend = 0;
91                    self.relocs.push(Relocation {
92                        kind,
93                        reloc_target,
94                        offset,
95                        addend,
96                    });
97                    self.write_udata(addend as _, size)
98                } else if symbol == Self::PERSONALITY_SYMBOL {
99                    let offset = self.len() as u32;
100                    let kind = match size {
101                        4 => RelocationKind::Abs4,
102                        8 => RelocationKind::Abs8,
103                        other => unimplemented!(
104                            "dwarf relocation size for personality not supported: {}",
105                            other
106                        ),
107                    };
108                    self.relocs.push(Relocation {
109                        kind,
110                        reloc_target: RelocationTarget::LibCall(LibCall::EHPersonality),
111                        offset,
112                        addend,
113                    });
114                    self.write_udata(0, size)
115                } else if let Some((target, base)) = self.lsda_symbols.get(&symbol) {
116                    let offset = self.len() as u32;
117                    let kind = match size {
118                        4 => RelocationKind::Abs4,
119                        8 => RelocationKind::Abs8,
120                        other => unimplemented!(
121                            "dwarf relocation size for LSDA not supported: {}",
122                            other
123                        ),
124                    };
125                    self.relocs.push(Relocation {
126                        kind,
127                        reloc_target: *target,
128                        offset,
129                        addend: *base as i64 + addend,
130                    });
131                    self.write_udata(0, size)
132                } else {
133                    unreachable!("Symbol {} in DWARF not recognized", symbol);
134                }
135            }
136        }
137    }
138
139    fn write_eh_pointer(
140        &mut self,
141        address: Address,
142        eh_pe: constants::DwEhPe,
143        size: u8,
144    ) -> Result<()> {
145        if eh_pe == constants::DW_EH_PE_absptr {
146            self.write_address(address, size)
147        } else {
148            match address {
149                Address::Constant(_) => self.writer.write_eh_pointer(address, eh_pe, size),
150                Address::Symbol { .. } => {
151                    unimplemented!("eh pointer encoding {eh_pe:?} not supported for symbol targets")
152                }
153            }
154        }
155    }
156
157    fn write_offset(&mut self, _val: usize, _section: SectionId, _size: u8) -> Result<()> {
158        unimplemented!("write_offset not yet implemented");
159    }
160
161    fn write_offset_at(
162        &mut self,
163        _offset: usize,
164        _val: usize,
165        _section: SectionId,
166        _size: u8,
167    ) -> Result<()> {
168        unimplemented!("write_offset_at not yet implemented");
169    }
170}