From 3a0e1a5d90346e0903725839a1b380ae427ce1af Mon Sep 17 00:00:00 2001 From: Lewis Revill Date: Wed, 12 Jun 2024 16:44:48 +0100 Subject: [PATCH] feat: Access references to globals through a custom GOT This commit introduces the association of GOT indices to the LLVM index, which then allows us to utilise that when generating references to variables to check if a given variable has an entry in the GOT. If so, we obtain its index, and generate the necessary LLVM IR to access the address contained within the GOT rather than accessing the variable directly. --- .../generators/expression_generator.rs | 48 +++++++++++++++++-- src/codegen/generators/variable_generator.rs | 2 + src/codegen/llvm_index.rs | 21 ++++++++ 3 files changed, 67 insertions(+), 4 deletions(-) diff --git a/src/codegen/generators/expression_generator.rs b/src/codegen/generators/expression_generator.rs index 404526afd6..782d6838b1 100644 --- a/src/codegen/generators/expression_generator.rs +++ b/src/codegen/generators/expression_generator.rs @@ -282,6 +282,42 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { self.generate_expression_value(const_expression) } + /// Generate an access to the appropriate GOT entry to achieve an access to the given base + /// lvalue. + pub fn generate_got_access( + &self, + context: &AstNode, + llvm_type: &BasicTypeEnum<'ink>, + ) -> Result>, Diagnostic> { + match self.annotations.get(context) { + Some(StatementAnnotation::Variable { qualified_name, .. }) => { + // We will generate a GEP, which has as its base address the magic constant which + // will eventually be replaced by the location of the GOT. + let base = self + .llvm + .context + .i64_type() + .const_int(0xdeadbeef00000000, false) + .const_to_pointer(llvm_type + .ptr_type(AddressSpace::default()) + .ptr_type(AddressSpace::default())); + + self.llvm_index + .find_got_index(qualified_name) + .map(|idx| { + let ptr = self.llvm.load_array_element( + base, + &[self.llvm.context.i32_type().const_int(idx, false)], + "", + )?; + Ok(self.llvm.load_pointer(&ptr, "").into_pointer_value()) + }) + .transpose() + } + _ => Ok(None), + } + } + /// generates a binary expression (e.g. a + b, x AND y, etc.) and returns the resulting `BasicValueEnum` /// - `left` the AstStatement left of the operator /// - `right` the AstStatement right of the operator @@ -1218,13 +1254,17 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> { } } + let ctx_type = + self.annotations.get_type_or_void(context, self.index).get_type_information(); + // no context ... so just something like 'x' match self.annotations.get(context) { Some(StatementAnnotation::Variable { qualified_name, .. }) - | Some(StatementAnnotation::Program { qualified_name, .. }) => self - .llvm_index - .find_loaded_associated_variable_value(qualified_name) - .ok_or_else(|| Diagnostic::unresolved_reference(name, offset.clone())), + | Some(StatementAnnotation::Program { qualified_name, .. }) => + self.generate_got_access(context, &self.llvm_index.get_associated_type(ctx_type.get_name())?)?.map_or(self + .llvm_index + .find_loaded_associated_variable_value(qualified_name) + .ok_or_else(|| Diagnostic::unresolved_reference(name, offset.clone())), Ok), _ => Err(Diagnostic::unresolved_reference(name, offset.clone())), } } diff --git a/src/codegen/generators/variable_generator.rs b/src/codegen/generators/variable_generator.rs index 9bd3928c7a..760cb41f8f 100644 --- a/src/codegen/generators/variable_generator.rs +++ b/src/codegen/generators/variable_generator.rs @@ -149,6 +149,7 @@ impl<'ctx, 'b> VariableGenerator<'ctx, 'b> { for (name, _) in &globals { if let Some(idx) = got_entries.get(&name.to_string()) { new_got_entries.insert(name.to_string(), *idx); + index.associate_got_index(name, *idx); new_got.insert(*idx, name.to_string()); } else { new_globals.push(name.to_string()); @@ -162,6 +163,7 @@ impl<'ctx, 'b> VariableGenerator<'ctx, 'b> { idx += 1; } new_got_entries.insert(name.to_string(), idx); + index.associate_got_index(name, idx); new_got.insert(idx, name.to_string()); } diff --git a/src/codegen/llvm_index.rs b/src/codegen/llvm_index.rs index b30d428c23..86604411a0 100644 --- a/src/codegen/llvm_index.rs +++ b/src/codegen/llvm_index.rs @@ -14,6 +14,7 @@ pub struct LlvmTypedIndex<'ink> { type_associations: FxHashMap>, pou_type_associations: FxHashMap>, global_values: FxHashMap>, + got_indices: FxHashMap, initial_value_associations: FxHashMap>, loaded_variable_associations: FxHashMap>, implementations: FxHashMap>, @@ -29,6 +30,7 @@ impl<'ink> LlvmTypedIndex<'ink> { type_associations: FxHashMap::default(), pou_type_associations: FxHashMap::default(), global_values: FxHashMap::default(), + got_indices: FxHashMap::default(), initial_value_associations: FxHashMap::default(), loaded_variable_associations: FxHashMap::default(), implementations: FxHashMap::default(), @@ -51,6 +53,9 @@ impl<'ink> LlvmTypedIndex<'ink> { for (name, value) in other.global_values.drain() { self.global_values.insert(name, value); } + for (name, index) in other.got_indices.drain() { + self.got_indices.insert(name, index); + } for (name, assocication) in other.initial_value_associations.drain() { self.initial_value_associations.insert(name, assocication); } @@ -110,6 +115,13 @@ impl<'ink> LlvmTypedIndex<'ink> { .or_else(|| self.parent_index.and_then(|it| it.find_global_value(name))) } + pub fn find_got_index(&self, name: &str) -> Option { + self.got_indices + .get(&name.to_lowercase()) + .copied() + .or_else(|| self.parent_index.and_then(|it| it.find_got_index(name))) + } + pub fn find_associated_type(&self, type_name: &str) -> Option> { self.type_associations .get(&type_name.to_lowercase()) @@ -153,6 +165,15 @@ impl<'ink> LlvmTypedIndex<'ink> { Ok(()) } + pub fn associate_got_index( + &mut self, + variable_name: &str, + index: u64, + ) -> Result<(), Diagnostic> { + self.got_indices.insert(variable_name.to_lowercase(), index); + Ok(()) + } + pub fn associate_implementation( &mut self, callable_name: &str,