Unverified Commit ba5a07a7 authored by Jeremy Soller's avatar Jeremy Soller Committed by GitHub

Merge pull request #1 from dlrobertson/aarch64_valist

Updates
parents 1945668b 1ead8f81
......@@ -7,4 +7,4 @@ description = "Test helper for the `va_list` crate. Not for user consumption."
license = "MIT"
[build-dependencies]
gcc = "0.3"
cc = "1.0"
extern crate gcc;
extern crate cc;
fn main() {
::gcc::compile_library("libva_list_test.a", &["src/helper.c"]);
::cc::Build::new()
.file("src/helper.c")
.compile("libva_list_test.a");
}
use std::{mem, ptr};
use super::VaPrimitive;
pub struct VaList(*mut VaListInner);
#[repr(C)]
#[derive(Debug)]
#[doc(hidden)]
pub struct VaListInner {
stack: *const (),
gr_top: *const (),
vr_top: *const (),
gr_offs: i32,
vr_offs: i32,
}
impl VaList {
fn inner(&mut self) -> &mut VaListInner {
// This pointer should be valid
unsafe { &mut *self.0 }
}
}
impl VaListInner {
pub unsafe fn get_gr<T>(&mut self) -> T {
assert!(!self.gr_top.is_null());
let rv = ptr::read((self.gr_top as usize - self.gr_offs.abs() as usize) as *const _);
self.gr_offs += 8;
rv
}
pub unsafe fn get_vr<T>(&mut self) -> T {
assert!(!self.vr_top.is_null());
let rv = ptr::read((self.vr_top as usize - self.vr_offs.abs() as usize) as *const _);
self.vr_offs += 16;
rv
}
}
impl<T: 'static> VaPrimitive for *const T {
unsafe fn get(list: &mut VaList) -> Self {
<usize>::get(list) as *const T
}
}
macro_rules! impl_va_prim_gr {
($u: ty, $s: ty) => {
impl VaPrimitive for $u {
unsafe fn get(list: &mut VaList) -> Self {
list.inner().get_gr()
}
}
impl VaPrimitive for $s {
unsafe fn get(list: &mut VaList) -> Self {
mem::transmute(<$u>::get(list))
}
}
};
}
macro_rules! impl_va_prim_vr {
($($t:ty),+) => {
$(
impl VaPrimitive for $t {
unsafe fn get(list: &mut VaList) -> Self {
list.inner().get_vr()
}
}
)+
};
}
impl_va_prim_gr!{ usize, isize }
impl_va_prim_gr!{ u64, i64 }
impl_va_prim_gr!{ u32, i32 }
impl_va_prim_vr!{ f64, f32 }
/*
*
*/
use std::{mem,ptr};
use std::{mem, ptr};
use super::VaPrimitive;
#[allow(non_camel_case_types)]
pub struct VaList(*const u8);
impl VaList
{
pub unsafe fn get<T: VaPrimitive>(&mut self) -> T {
T::get(self)
}
// Read a raw value from the list
unsafe fn get_raw<T: 'static>(&mut self) -> T {
assert_eq!(self.0 as usize % mem::align_of::<T>(), 0);
let rv = ptr::read(self.0 as *const T);
self.0 = self.0.offset( mem::size_of::<T>() as isize );
rv
}
impl VaList {
pub unsafe fn get<T: VaPrimitive>(&mut self) -> T {
T::get(self)
}
// Read a raw value from the list
unsafe fn get_raw<T: 'static>(&mut self) -> T {
assert_eq!(self.0 as usize % mem::align_of::<T>(), 0);
let rv = ptr::read(self.0 as *const T);
self.0 = self.0.offset(mem::size_of::<T>() as isize);
rv
}
}
impl<T: 'static> VaPrimitive for *const T
{
unsafe fn get(list: &mut VaList) -> Self {
<usize>::get(list) as *const T
}
}
impl VaPrimitive for usize { unsafe fn get(l: &mut VaList) -> Self { l.get_raw() } }
impl VaPrimitive for isize { unsafe fn get(l: &mut VaList) -> Self { l.get_raw() } }
impl VaPrimitive for u64 { unsafe fn get(l: &mut VaList) -> Self { l.get_raw() } }
impl VaPrimitive for i64 { unsafe fn get(l: &mut VaList) -> Self { l.get_raw() } }
impl VaPrimitive for u32 { unsafe fn get(l: &mut VaList) -> Self { l.get_raw() } }
impl VaPrimitive for i32 { unsafe fn get(l: &mut VaList) -> Self { l.get_raw() } }
impl<T: 'static> VaPrimitive for *const T {
unsafe fn get(list: &mut VaList) -> Self {
<usize>::get(list) as *const T
}
}
impl VaPrimitive for usize {
unsafe fn get(l: &mut VaList) -> Self {
l.get_raw()
}
}
impl VaPrimitive for isize {
unsafe fn get(l: &mut VaList) -> Self {
l.get_raw()
}
}
impl VaPrimitive for u64 {
unsafe fn get(l: &mut VaList) -> Self {
l.get_raw()
}
}
impl VaPrimitive for i64 {
unsafe fn get(l: &mut VaList) -> Self {
l.get_raw()
}
}
impl VaPrimitive for u32 {
unsafe fn get(l: &mut VaList) -> Self {
l.get_raw()
}
}
impl VaPrimitive for i32 {
unsafe fn get(l: &mut VaList) -> Self {
l.get_raw()
}
}
//impl VaPrimitive for u16 { unsafe fn get(l: &mut VaList) -> Self { l.get_raw() } }
//impl VaPrimitive for i16 { unsafe fn get(l: &mut VaList) -> Self { l.get_raw() } }
//impl VaPrimitive for u8 { unsafe fn get(l: &mut VaList) -> Self { l.get_raw() } }
//impl VaPrimitive for i8 { unsafe fn get(l: &mut VaList) -> Self { l.get_raw() } }
impl VaPrimitive for f64 { unsafe fn get(l: &mut VaList) -> Self { l.get_raw() } }
impl VaPrimitive for f64 {
unsafe fn get(l: &mut VaList) -> Self {
l.get_raw()
}
}
//impl VaPrimitive for f32 { unsafe fn get(l: &mut VaList) -> Self { l.get_raw() } }
/*
*
*/
use std::{mem,ptr};
use std::{mem, ptr};
use super::VaPrimitive;
#[allow(non_camel_case_types)]
pub struct VaList(*const u8);
impl VaList
{
pub unsafe fn get<T: VaPrimitive>(&mut self) -> T {
T::get(self)
}
// Read a raw value from the list
unsafe fn get_raw<T: 'static>(&mut self) -> T {
assert_eq!(self.0 as usize % mem::align_of::<T>(), 0);
let rv = ptr::read(self.0 as *const T);
self.0 = self.0.offset( mem::size_of::<T>() as isize );
rv
}
impl VaList {
pub unsafe fn get<T: VaPrimitive>(&mut self) -> T {
T::get(self)
}
// Read a raw value from the list
unsafe fn get_raw<T: 'static>(&mut self) -> T {
assert_eq!(self.0 as usize % mem::align_of::<T>(), 0);
let rv = ptr::read(self.0 as *const T);
self.0 = self.0.offset(mem::size_of::<T>() as isize);
rv
}
}
impl<T: 'static> VaPrimitive for *const T
{
unsafe fn get(list: &mut VaList) -> Self {
<usize>::get(list) as *const T
}
}
impl VaPrimitive for usize { unsafe fn get(l: &mut VaList) -> Self { l.get_raw() } }
impl VaPrimitive for isize { unsafe fn get(l: &mut VaList) -> Self { l.get_raw() } }
impl VaPrimitive for u64 { unsafe fn get(l: &mut VaList) -> Self { l.get_raw() } }
impl VaPrimitive for i64 { unsafe fn get(l: &mut VaList) -> Self { l.get_raw() } }
impl VaPrimitive for u32 { unsafe fn get(l: &mut VaList) -> Self { l.get_raw() } }
impl VaPrimitive for i32 { unsafe fn get(l: &mut VaList) -> Self { l.get_raw() } }
impl<T: 'static> VaPrimitive for *const T {
unsafe fn get(list: &mut VaList) -> Self {
<usize>::get(list) as *const T
}
}
impl VaPrimitive for usize {
unsafe fn get(l: &mut VaList) -> Self {
l.get_raw()
}
}
impl VaPrimitive for isize {
unsafe fn get(l: &mut VaList) -> Self {
l.get_raw()
}
}
impl VaPrimitive for u64 {
unsafe fn get(l: &mut VaList) -> Self {
l.get_raw()
}
}
impl VaPrimitive for i64 {
unsafe fn get(l: &mut VaList) -> Self {
l.get_raw()
}
}
impl VaPrimitive for u32 {
unsafe fn get(l: &mut VaList) -> Self {
l.get_raw()
}
}
impl VaPrimitive for i32 {
unsafe fn get(l: &mut VaList) -> Self {
l.get_raw()
}
}
//impl VaPrimitive for u16 { unsafe fn get(l: &mut VaList) -> Self { l.get_raw() } }
//impl VaPrimitive for i16 { unsafe fn get(l: &mut VaList) -> Self { l.get_raw() } }
//impl VaPrimitive for u8 { unsafe fn get(l: &mut VaList) -> Self { l.get_raw() } }
//impl VaPrimitive for i8 { unsafe fn get(l: &mut VaList) -> Self { l.get_raw() } }
impl VaPrimitive for f64 { unsafe fn get(l: &mut VaList) -> Self { l.get_raw() } }
impl VaPrimitive for f64 {
unsafe fn get(l: &mut VaList) -> Self {
l.get_raw()
}
}
//impl VaPrimitive for f32 { unsafe fn get(l: &mut VaList) -> Self { l.get_raw() } }
// x86_64 ELF - Aka the Itanium ABI
//
use std::{mem,ptr};
use std::{mem, ptr};
use super::VaPrimitive;
pub struct VaList(*mut VaListInner);
......@@ -10,91 +10,89 @@ pub struct VaList(*mut VaListInner);
#[repr(C)]
#[derive(Debug)]
#[doc(hidden)]
pub struct VaListInner
{
gp_offset: u32,
fp_offset: u32,
overflow_arg_area: *const (),
reg_save_area: *const (),
pub struct VaListInner {
gp_offset: u32,
fp_offset: u32,
overflow_arg_area: *const (),
reg_save_area: *const (),
}
impl VaList
{
fn inner(&mut self) -> &mut VaListInner {
// This pointer should be valid
unsafe { &mut *self.0 }
}
impl VaList {
fn inner(&mut self) -> &mut VaListInner {
// This pointer should be valid
unsafe { &mut *self.0 }
}
}
#[doc(hidden)]
impl VaListInner
{
fn check_space(&self, num_gp: u32, num_fp: u32) -> bool {
!(self.gp_offset > 48 - num_gp * 8 || self.fp_offset > 304 - num_fp * 16)
}
unsafe fn get_gp<T>(&mut self) -> T {
let n_gp = (mem::size_of::<T>()+7)/8;
assert!( self.check_space(n_gp as u32, 0) );
let rv = ptr::read( (self.reg_save_area as usize + self.gp_offset as usize) as *const _ );
self.gp_offset += (8*n_gp) as u32;
rv
}
unsafe fn get_fp<T>(&mut self) -> T {
let n_fp = (mem::size_of::<T>()+15)/16;
assert!( self.check_space(0, n_fp as u32) );
let rv = ptr::read( (self.reg_save_area as usize + self.fp_offset as usize) as *const _ );
self.fp_offset += (16*n_fp) as u32;
rv
}
unsafe fn get_overflow<T>(&mut self) -> T {
let align = mem::align_of::<T>();
// 7. Align overflow_reg_area upwards to a 16-byte boundary if alignment
// needed by T exceeds 8 bytes
let addr = self.overflow_arg_area as usize;
if align > 8 {
if addr % 16 != 0 {
self.overflow_arg_area = ((addr + 15) & !(16-1)) as *const _;
}
}
else {
if addr % 8 != 0 {
self.overflow_arg_area = ((addr + 7) & !(8-1)) as *const _;
}
}
// 8. Fetch from overflow areay
let rv = ptr::read( self.overflow_arg_area as *const _ );
self.overflow_arg_area = ((self.overflow_arg_area as usize) + mem::size_of::<T>()) as *const _;
rv
}
impl VaListInner {
fn check_space(&self, num_gp: u32, num_fp: u32) -> bool {
!(self.gp_offset > 48 - num_gp * 8 || self.fp_offset > 304 - num_fp * 16)
}
unsafe fn get_gp<T>(&mut self) -> T {
let n_gp = (mem::size_of::<T>() + 7) / 8;
assert!(self.check_space(n_gp as u32, 0));
let rv = ptr::read((self.reg_save_area as usize + self.gp_offset as usize) as *const _);
self.gp_offset += (8 * n_gp) as u32;
rv
}
unsafe fn get_fp<T>(&mut self) -> T {
let n_fp = (mem::size_of::<T>() + 15) / 16;
assert!(self.check_space(0, n_fp as u32));
let rv = ptr::read((self.reg_save_area as usize + self.fp_offset as usize) as *const _);
self.fp_offset += (16 * n_fp) as u32;
rv
}
unsafe fn get_overflow<T>(&mut self) -> T {
let align = mem::align_of::<T>();
// 7. Align overflow_reg_area upwards to a 16-byte boundary if alignment
// needed by T exceeds 8 bytes
let addr = self.overflow_arg_area as usize;
if align > 8 {
if addr % 16 != 0 {
self.overflow_arg_area = ((addr + 15) & !(16 - 1)) as *const _;
}
} else {
if addr % 8 != 0 {
self.overflow_arg_area = ((addr + 7) & !(8 - 1)) as *const _;
}
}
// 8. Fetch from overflow areay
let rv = ptr::read(self.overflow_arg_area as *const _);
self.overflow_arg_area =
((self.overflow_arg_area as usize) + mem::size_of::<T>()) as *const _;
rv
}
}
impl<T: 'static> VaPrimitive for *const T
{
unsafe fn get(list: &mut VaList) -> Self {
<usize>::get(list) as *const T
}
impl<T: 'static> VaPrimitive for *const T {
unsafe fn get(list: &mut VaList) -> Self {
<usize>::get(list) as *const T
}
}
macro_rules! impl_va_prim {
($u:ty, $s:ty) => {
impl VaPrimitive for $u {
unsafe fn get(list: &mut VaList) -> Self {
let inner = list.inner();
// See the ELF AMD64 ABI document for a description of how this should act
if ! inner.check_space(1, 0) {
inner.get_overflow()
}
else {
inner.get_gp()
}
}
}
impl VaPrimitive for $s {
unsafe fn get(list: &mut VaList) -> Self {
mem::transmute( <$u>::get(list) )
}
}
};
($u: ty, $s: ty) => {
impl VaPrimitive for $u {
unsafe fn get(list: &mut VaList) -> Self {
let inner = list.inner();
// See the ELF AMD64 ABI document for a description of how this should act
if !inner.check_space(1, 0) {
inner.get_overflow()
} else {
inner.get_gp()
}
}
}
impl VaPrimitive for $s {
unsafe fn get(list: &mut VaList) -> Self {
mem::transmute(<$u>::get(list))
}
}
};
}
impl_va_prim!{ usize, isize }
......@@ -104,14 +102,13 @@ impl_va_prim!{ u32, i32 }
//impl_va_prim!{ u8, i8 }
impl VaPrimitive for f64 {
unsafe fn get(list: &mut VaList) -> Self {
let inner = list.inner();
// See the ELF AMD64 ABI document for a description of how this should act
if ! inner.check_space(0, 1) {
inner.get_overflow()
}
else {
inner.get_fp()
}
}
unsafe fn get(list: &mut VaList) -> Self {
let inner = list.inner();
// See the ELF AMD64 ABI document for a description of how this should act
if !inner.check_space(0, 1) {
inner.get_overflow()
} else {
inner.get_fp()
}
}
}
/*
*
*/
use std::{mem,ptr};
use std::{mem, ptr};
use super::VaPrimitive;
#[allow(non_camel_case_types)]
pub struct VaList(*const u8);
impl VaList
{
// Read a raw value from the list
unsafe fn get_raw<T: 'static>(&mut self) -> T {
assert_eq!(self.0 as usize % mem::align_of::<T>(), 0);
let rv = ptr::read(self.0 as *const T);
self.0 = self.0.offset( mem::size_of::<T>() as isize );
rv
}
impl VaList {
// Read a raw value from the list
unsafe fn get_raw<T: 'static>(&mut self) -> T {
assert_eq!(self.0 as usize % mem::align_of::<T>(), 0);
let rv = ptr::read(self.0 as *const T);
self.0 = self.0.offset(mem::size_of::<T>() as isize);
rv
}
}
impl<T: 'static> VaPrimitive for *const T
{
unsafe fn get(list: &mut VaList) -> Self {
<usize>::get(list) as *const T
}
}
impl VaPrimitive for usize { unsafe fn get(l: &mut VaList) -> Self { l.get_raw() } }
impl VaPrimitive for isize { unsafe fn get(l: &mut VaList) -> Self { l.get_raw() } }
impl VaPrimitive for u64 { unsafe fn get(l: &mut VaList) -> Self { l.get_raw() } }
impl VaPrimitive for i64 { unsafe fn get(l: &mut VaList) -> Self { l.get_raw() } }
impl VaPrimitive for u32 { unsafe fn get(l: &mut VaList) -> Self { l.get_raw::<u64>() as u32 } }
impl VaPrimitive for i32 { unsafe fn get(l: &mut VaList) -> Self { l.get_raw::<i64>() as i32 } }
impl<T: 'static> VaPrimitive for *const T {
unsafe fn get(list: &mut VaList) -> Self {
<usize>::get(list) as *const T
}
}
impl VaPrimitive for usize {
unsafe fn get(l: &mut VaList) -> Self {
l.get_raw()
}
}
impl VaPrimitive for isize {
unsafe fn get(l: &mut VaList) -> Self {
l.get_raw()
}
}
impl VaPrimitive for u64 {
unsafe fn get(l: &mut VaList) -> Self {
l.get_raw()
}
}
impl VaPrimitive for i64 {
unsafe fn get(l: &mut VaList) -> Self {
l.get_raw()
}
}
impl VaPrimitive for u32 {
unsafe fn get(l: &mut VaList) -> Self {
l.get_raw::<u64>() as u32
}
}
impl VaPrimitive for i32 {
unsafe fn get(l: &mut VaList) -> Self {
l.get_raw::<i64>() as i32
}
}
//impl VaPrimitive for u16 { unsafe fn get(l: &mut VaList) -> Self { l.get_raw() } }
//impl VaPrimitive for i16 { unsafe fn get(l: &mut VaList) -> Self { l.get_raw() } }
//impl VaPrimitive for u8 { unsafe fn get(l: &mut VaList) -> Self { l.get_raw() } }
//impl VaPrimitive for i8 { unsafe fn get(l: &mut VaList) -> Self { l.get_raw() } }
impl VaPrimitive for f64 { unsafe fn get(l: &mut VaList) -> Self { l.get_raw() } }
impl VaPrimitive for f64 {
unsafe fn get(l: &mut VaList) -> Self {
l.get_raw()
}
}
......@@ -33,52 +33,60 @@
* }
* ```
*/
#![cfg_attr(feature="no_std",no_std)]
#![crate_type="lib"]
#![crate_name="va_list"]
#![cfg_attr(feature = "no_std", no_std)]
#![crate_type = "lib"]
#![crate_name = "va_list"]
#[cfg(feature="no_std")]
#[cfg(feature = "no_std")]
#[doc(hidden)]
mod std {
pub use core::{mem,ptr};
pub use core::{mem, ptr};
}
// x86_64 on unix platforms is _usually_ ELF.
#[cfg(all( target_arch="x86_64", any(target_family="unix", target_os="redox", target_os="tifflin") ))]
#[path="impl-x86_64-elf.rs"] mod imp;
#[cfg(all(target_arch = "x86_64",
any(target_family = "unix", target_os = "redox", target_os = "tifflin")))]
#[path = "impl-x86_64-elf.rs"]
mod imp;
//// x86_64 on windows is special
#[cfg(all( target_arch="x86_64", target_family="windows" ))]
#[path="impl-x86_64-win64.rs"] mod imp;
#[cfg(all(target_arch = "x86_64", target_family = "windows"))]
#[path = "impl-x86_64-win64.rs"]
mod imp;
// x86+unix = cdecl
#[cfg(all( target_arch="x86", target_family="unix" ))]
#[path="impl-x86-sysv.rs"] mod imp;
#[cfg(all(target_arch = "x86", target_family = "unix"))]
#[path = "impl-x86-sysv.rs"]
mod imp;
// aarch64
#[cfg(all(target_arch = "aarch64", any(target_family = "unix", target_os = "redox")))]
#[path = "impl-aarch64-elf.rs"]
mod imp;
// arm+unix = cdecl
#[cfg(all( target_arch="arm", target_family="unix" ))]
#[path="impl-arm-sysv.rs"] mod imp;
#[cfg(all(target_arch = "arm", target_family = "unix"))]
#[path = "impl-arm-sysv.rs"]
mod imp;
/// Rust version of C's `va_list` type from the `stdarg.h` header
#[repr(C)]
pub struct VaList {
internal: imp::VaList