Skip to content

Commit

Permalink
feat: Access references to globals through a custom GOT
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
lewis-revill committed Jun 19, 2024
1 parent d9c4561 commit 3a0e1a5
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 4 deletions.
48 changes: 44 additions & 4 deletions src/codegen/generators/expression_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Option<PointerValue<'ink>>, 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
Expand Down Expand Up @@ -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())),
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/codegen/generators/variable_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand All @@ -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());
}

Expand Down
21 changes: 21 additions & 0 deletions src/codegen/llvm_index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub struct LlvmTypedIndex<'ink> {
type_associations: FxHashMap<String, BasicTypeEnum<'ink>>,
pou_type_associations: FxHashMap<String, BasicTypeEnum<'ink>>,
global_values: FxHashMap<String, GlobalValue<'ink>>,
got_indices: FxHashMap<String, u64>,
initial_value_associations: FxHashMap<String, BasicValueEnum<'ink>>,
loaded_variable_associations: FxHashMap<String, PointerValue<'ink>>,
implementations: FxHashMap<String, FunctionValue<'ink>>,
Expand All @@ -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(),
Expand All @@ -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);
}
Expand Down Expand Up @@ -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<u64> {
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<BasicTypeEnum<'ink>> {
self.type_associations
.get(&type_name.to_lowercase())
Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit 3a0e1a5

Please sign in to comment.