Add a new kind of GlobalVar for symbolic addresses.
These addresses will allow referencing C/C++/Rust-style global variables by name directly.
This commit is contained in:
@@ -563,6 +563,16 @@ runtime data structures.
|
|||||||
variable.
|
variable.
|
||||||
:result GV: Global variable.
|
:result GV: Global variable.
|
||||||
|
|
||||||
|
.. inst:: GV = globalsym name
|
||||||
|
|
||||||
|
Declare a global variable at a symbolic address.
|
||||||
|
|
||||||
|
The address of GV is symbolic and will be assigned a relocation, so that
|
||||||
|
it can be resolved by a later linking phase.
|
||||||
|
|
||||||
|
:arg name: External name.
|
||||||
|
:result GV: Global variable.
|
||||||
|
|
||||||
.. autoinst:: global_addr
|
.. autoinst:: global_addr
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,20 @@ ebb0:
|
|||||||
return v1
|
return v1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function %sym() -> i32 {
|
||||||
|
gv0 = globalsym %something
|
||||||
|
; check: $gv0 = globalsym %something
|
||||||
|
gv1 = globalsym #d0bad180d0b5d182d0bed0bd
|
||||||
|
; check: $gv1 = globalsym #d0bad180d0b5d182d0bed0bd
|
||||||
|
ebb0:
|
||||||
|
v0 = global_addr.i32 gv0
|
||||||
|
; check: $v0 = global_addr.i32 $gv0
|
||||||
|
v1 = global_addr.i32 gv1
|
||||||
|
; check: $v1 = global_addr.i32 $gv1
|
||||||
|
v2 = bxor v0, v1
|
||||||
|
return v2
|
||||||
|
}
|
||||||
|
|
||||||
; Declare static heaps.
|
; Declare static heaps.
|
||||||
function %sheap(i32) -> i64 {
|
function %sheap(i32) -> i64 {
|
||||||
heap1 = static reserved_reg, min 0x1_0000, bound 0x1_0000_0000, guard 0x8000_0000
|
heap1 = static reserved_reg, min 0x1_0000, bound 0x1_0000_0000, guard 0x8000_0000
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
//! Global variables.
|
//! Global variables.
|
||||||
|
|
||||||
use ir::GlobalVar;
|
use ir::{ExternalName, GlobalVar};
|
||||||
use ir::immediates::Offset32;
|
use ir::immediates::Offset32;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
@@ -25,6 +25,14 @@ pub enum GlobalVarData {
|
|||||||
/// Byte offset to be added to the pointer loaded from `base`.
|
/// Byte offset to be added to the pointer loaded from `base`.
|
||||||
offset: Offset32,
|
offset: Offset32,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// Variable is at an address identified by a symbolic name. Cretonne itself
|
||||||
|
/// does not interpret this name; it's used by embedders to link with other
|
||||||
|
/// data structures.
|
||||||
|
Sym {
|
||||||
|
/// The symbolic name.
|
||||||
|
name: ExternalName,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for GlobalVarData {
|
impl fmt::Display for GlobalVarData {
|
||||||
@@ -32,6 +40,7 @@ impl fmt::Display for GlobalVarData {
|
|||||||
match *self {
|
match *self {
|
||||||
GlobalVarData::VmCtx { offset } => write!(f, "vmctx{}", offset),
|
GlobalVarData::VmCtx { offset } => write!(f, "vmctx{}", offset),
|
||||||
GlobalVarData::Deref { base, offset } => write!(f, "deref({}){}", base, offset),
|
GlobalVarData::Deref { base, offset } => write!(f, "deref({}){}", base, offset),
|
||||||
|
GlobalVarData::Sym { ref name } => write!(f, "globalsym {}", name),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ pub fn expand_global_addr(inst: ir::Inst, func: &mut ir::Function, _cfg: &mut Co
|
|||||||
match func.global_vars[gv] {
|
match func.global_vars[gv] {
|
||||||
ir::GlobalVarData::VmCtx { offset } => vmctx_addr(inst, func, offset.into()),
|
ir::GlobalVarData::VmCtx { offset } => vmctx_addr(inst, func, offset.into()),
|
||||||
ir::GlobalVarData::Deref { base, offset } => deref_addr(inst, func, base, offset.into()),
|
ir::GlobalVarData::Deref { base, offset } => deref_addr(inst, func, base, offset.into()),
|
||||||
|
ir::GlobalVarData::Sym { .. } => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -877,7 +877,7 @@ impl<'a> Parser<'a> {
|
|||||||
let location = self.loc;
|
let location = self.loc;
|
||||||
|
|
||||||
// function-spec ::= "function" * name signature
|
// function-spec ::= "function" * name signature
|
||||||
let name = self.parse_function_name()?;
|
let name = self.parse_external_name()?;
|
||||||
|
|
||||||
// function-spec ::= "function" name * signature
|
// function-spec ::= "function" name * signature
|
||||||
let sig = self.parse_signature(unique_isa)?;
|
let sig = self.parse_signature(unique_isa)?;
|
||||||
@@ -885,11 +885,13 @@ impl<'a> Parser<'a> {
|
|||||||
Ok((location, name, sig))
|
Ok((location, name, sig))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse a function name.
|
// Parse an external name.
|
||||||
|
//
|
||||||
|
// For example, in a function spec, the parser would be in this state:
|
||||||
//
|
//
|
||||||
// function ::= "function" * name signature { ... }
|
// function ::= "function" * name signature { ... }
|
||||||
//
|
//
|
||||||
fn parse_function_name(&mut self) -> Result<ExternalName> {
|
fn parse_external_name(&mut self) -> Result<ExternalName> {
|
||||||
match self.token() {
|
match self.token() {
|
||||||
Some(Token::Name(s)) => {
|
Some(Token::Name(s)) => {
|
||||||
self.consume();
|
self.consume();
|
||||||
@@ -899,7 +901,7 @@ impl<'a> Parser<'a> {
|
|||||||
if s.len() % 2 != 0 {
|
if s.len() % 2 != 0 {
|
||||||
return err!(
|
return err!(
|
||||||
self.loc,
|
self.loc,
|
||||||
"expected binary function name to have length multiple of two"
|
"expected binary external name to have length multiple of two"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let mut bin_name = Vec::with_capacity(s.len() / 2);
|
let mut bin_name = Vec::with_capacity(s.len() / 2);
|
||||||
@@ -912,7 +914,7 @@ impl<'a> Parser<'a> {
|
|||||||
self.consume();
|
self.consume();
|
||||||
Ok(ExternalName::new(bin_name))
|
Ok(ExternalName::new(bin_name))
|
||||||
}
|
}
|
||||||
_ => err!(self.loc, "expected function name"),
|
_ => err!(self.loc, "expected external name"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1142,6 +1144,7 @@ impl<'a> Parser<'a> {
|
|||||||
// global-var-decl ::= * GlobalVar(gv) "=" global-var-desc
|
// global-var-decl ::= * GlobalVar(gv) "=" global-var-desc
|
||||||
// global-var-desc ::= "vmctx" offset32
|
// global-var-desc ::= "vmctx" offset32
|
||||||
// | "deref" "(" GlobalVar(base) ")" offset32
|
// | "deref" "(" GlobalVar(base) ")" offset32
|
||||||
|
// | "globalsym" name
|
||||||
//
|
//
|
||||||
fn parse_global_var_decl(&mut self) -> Result<(u32, GlobalVarData)> {
|
fn parse_global_var_decl(&mut self) -> Result<(u32, GlobalVarData)> {
|
||||||
let number = self.match_gv("expected global variable number: gv«n»")?;
|
let number = self.match_gv("expected global variable number: gv«n»")?;
|
||||||
@@ -1168,6 +1171,10 @@ impl<'a> Parser<'a> {
|
|||||||
let offset = self.optional_offset32()?;
|
let offset = self.optional_offset32()?;
|
||||||
GlobalVarData::Deref { base, offset }
|
GlobalVarData::Deref { base, offset }
|
||||||
}
|
}
|
||||||
|
"globalsym" => {
|
||||||
|
let name = self.parse_external_name()?;
|
||||||
|
GlobalVarData::Sym { name }
|
||||||
|
}
|
||||||
other => return err!(self.loc, "Unknown global variable kind '{}'", other),
|
other => return err!(self.loc, "Unknown global variable kind '{}'", other),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1292,7 +1299,7 @@ impl<'a> Parser<'a> {
|
|||||||
Some(Token::SigRef(sig_src)) => {
|
Some(Token::SigRef(sig_src)) => {
|
||||||
let sig = ctx.get_sig(sig_src, &self.loc)?;
|
let sig = ctx.get_sig(sig_src, &self.loc)?;
|
||||||
self.consume();
|
self.consume();
|
||||||
let name = self.parse_function_name()?;
|
let name = self.parse_external_name()?;
|
||||||
ExtFuncData {
|
ExtFuncData {
|
||||||
name,
|
name,
|
||||||
signature: sig,
|
signature: sig,
|
||||||
|
|||||||
Reference in New Issue
Block a user