Implement SystemV struct argument passing
This commit is contained in:
@@ -282,6 +282,9 @@ pub enum ArgumentPurpose {
|
||||
/// A normal user program value passed to or from a function.
|
||||
Normal,
|
||||
|
||||
/// A C struct passed as argument.
|
||||
StructArgument(u32),
|
||||
|
||||
/// Struct return pointer.
|
||||
///
|
||||
/// When a function needs to return more data than will fit in registers, the caller passes a
|
||||
@@ -334,21 +337,19 @@ pub enum ArgumentPurpose {
|
||||
StackLimit,
|
||||
}
|
||||
|
||||
/// Text format names of the `ArgumentPurpose` variants.
|
||||
static PURPOSE_NAMES: [&str; 8] = [
|
||||
"normal",
|
||||
"sret",
|
||||
"link",
|
||||
"fp",
|
||||
"csr",
|
||||
"vmctx",
|
||||
"sigid",
|
||||
"stack_limit",
|
||||
];
|
||||
|
||||
impl fmt::Display for ArgumentPurpose {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str(PURPOSE_NAMES[*self as usize])
|
||||
f.write_str(match self {
|
||||
Self::Normal => "normal",
|
||||
Self::StructArgument(size) => return write!(f, "sarg({})", size),
|
||||
Self::StructReturn => "sret",
|
||||
Self::Link => "link",
|
||||
Self::FramePointer => "fp",
|
||||
Self::CalleeSaved => "csr",
|
||||
Self::VMContext => "vmctx",
|
||||
Self::SignatureId => "sigid",
|
||||
Self::StackLimit => "stack_limit",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -364,6 +365,13 @@ impl FromStr for ArgumentPurpose {
|
||||
"vmctx" => Ok(Self::VMContext),
|
||||
"sigid" => Ok(Self::SignatureId),
|
||||
"stack_limit" => Ok(Self::StackLimit),
|
||||
_ if s.starts_with("sarg(") => {
|
||||
if !s.ends_with(")") {
|
||||
return Err(());
|
||||
}
|
||||
let size: u32 = s["sarg(".len()..s.len() - 1].parse().map_err(|_| ())?;
|
||||
Ok(Self::StructArgument(size))
|
||||
}
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
@@ -436,16 +444,17 @@ mod tests {
|
||||
#[test]
|
||||
fn argument_purpose() {
|
||||
let all_purpose = [
|
||||
ArgumentPurpose::Normal,
|
||||
ArgumentPurpose::StructReturn,
|
||||
ArgumentPurpose::Link,
|
||||
ArgumentPurpose::FramePointer,
|
||||
ArgumentPurpose::CalleeSaved,
|
||||
ArgumentPurpose::VMContext,
|
||||
ArgumentPurpose::SignatureId,
|
||||
ArgumentPurpose::StackLimit,
|
||||
(ArgumentPurpose::Normal, "normal"),
|
||||
(ArgumentPurpose::StructReturn, "sret"),
|
||||
(ArgumentPurpose::Link, "link"),
|
||||
(ArgumentPurpose::FramePointer, "fp"),
|
||||
(ArgumentPurpose::CalleeSaved, "csr"),
|
||||
(ArgumentPurpose::VMContext, "vmctx"),
|
||||
(ArgumentPurpose::SignatureId, "sigid"),
|
||||
(ArgumentPurpose::StackLimit, "stack_limit"),
|
||||
(ArgumentPurpose::StructArgument(42), "sarg(42)"),
|
||||
];
|
||||
for (&e, &n) in all_purpose.iter().zip(PURPOSE_NAMES.iter()) {
|
||||
for &(e, n) in &all_purpose {
|
||||
assert_eq!(e.to_string(), n);
|
||||
assert_eq!(Ok(e), n.parse());
|
||||
}
|
||||
|
||||
@@ -287,7 +287,12 @@ impl StackSlots {
|
||||
|
||||
/// Create a stack slot representing an incoming function argument.
|
||||
pub fn make_incoming_arg(&mut self, ty: Type, offset: StackOffset) -> StackSlot {
|
||||
let mut data = StackSlotData::new(StackSlotKind::IncomingArg, ty.bytes());
|
||||
self.make_incoming_struct_arg(ty.bytes(), offset)
|
||||
}
|
||||
|
||||
/// Create a stack slot representing an incoming struct function argument.
|
||||
pub fn make_incoming_struct_arg(&mut self, size: u32, offset: StackOffset) -> StackSlot {
|
||||
let mut data = StackSlotData::new(StackSlotKind::IncomingArg, size);
|
||||
debug_assert!(offset <= StackOffset::max_value() - data.size as StackOffset);
|
||||
data.offset = Some(offset);
|
||||
self.push(data)
|
||||
@@ -301,8 +306,11 @@ impl StackSlots {
|
||||
/// The requested offset is relative to this function's stack pointer immediately before making
|
||||
/// the call.
|
||||
pub fn get_outgoing_arg(&mut self, ty: Type, offset: StackOffset) -> StackSlot {
|
||||
let size = ty.bytes();
|
||||
self.get_outgoing_struct_arg(ty.bytes(), offset)
|
||||
}
|
||||
|
||||
/// FIXME
|
||||
pub fn get_outgoing_struct_arg(&mut self, size: u32, offset: StackOffset) -> StackSlot {
|
||||
// Look for an existing outgoing stack slot with the same offset and size.
|
||||
let inspos = match self.outgoing.binary_search_by_key(&(offset, size), |&ss| {
|
||||
(self[ss].offset.unwrap(), self[ss].size)
|
||||
|
||||
@@ -343,6 +343,7 @@ impl Display for Type {
|
||||
f.write_str(match *self {
|
||||
IFLAGS => "iflags",
|
||||
FFLAGS => "fflags",
|
||||
SARG__ => "sarg__",
|
||||
INVALID => panic!("INVALID encountered"),
|
||||
_ => panic!("Unknown Type(0x{:x})", self.0),
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user