Implement SystemV struct argument passing

This commit is contained in:
bjorn3
2020-04-20 12:01:53 +02:00
committed by Benjamin Bouvier
parent 2f368ed5d6
commit 4431ac1108
15 changed files with 298 additions and 50 deletions

View File

@@ -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());
}

View File

@@ -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)

View File

@@ -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),
})