Skip to content

Commit

Permalink
Add the --override-abi option (#2329)
Browse files Browse the repository at this point in the history
* Add the `--override-abi` option.

This option can be used from the CLI with the <abi>:<regex> syntax and
it overrides the ABI of a function if it matches <regex>.

Fixes #2257
  • Loading branch information
pvdrz authored Nov 2, 2022
1 parent a673a6b commit 9c32b46
Show file tree
Hide file tree
Showing 8 changed files with 190 additions and 76 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@
# Unreleased

## Added
* new feature: `--override-abi` flag to override the ABI used by functions
matching a regular expression.

## Changed

Expand Down
18 changes: 18 additions & 0 deletions bindgen-cli/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,12 @@ where
Arg::new("merge-extern-blocks")
.long("merge-extern-blocks")
.help("Deduplicates extern blocks."),
Arg::new("override-abi")
.long("override-abi")
.help("Overrides the ABI of functions matching <regex>. The <override> value must be of the shape <abi>:<regex> where <abi> can be one of C, stdcall, fastcall, thiscall, aapcs or win64.")
.value_name("override")
.multiple_occurrences(true)
.number_of_values(1),
Arg::new("V")
.long("version")
.help("Prints the version, and exits"),
Expand Down Expand Up @@ -1088,5 +1094,17 @@ where
builder = builder.merge_extern_blocks(true);
}

if let Some(abi_overrides) = matches.values_of("override-abi") {
for abi_override in abi_overrides {
let (regex, abi_str) = abi_override
.rsplit_once("=")
.expect("Invalid ABI override: Missing `=`");
let abi = abi_str
.parse()
.unwrap_or_else(|err| panic!("Invalid ABI override: {}", err));
builder = builder.override_abi(abi, regex);
}
}

Ok((builder, output, verbose))
}
16 changes: 16 additions & 0 deletions bindgen-tests/tests/expectations/tests/abi-override.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions bindgen-tests/tests/headers/abi-override.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// bindgen-flags: --override-abi=foo=fastcall --override-abi=bar=stdcall

void foo();
void bar();
void baz();
6 changes: 3 additions & 3 deletions bindgen/codegen/dyngen.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::codegen;
use crate::ir::function::Abi;
use crate::ir::function::ClangAbi;
use proc_macro2::Ident;

/// Used to build the output tokens for dynamic bindings.
Expand Down Expand Up @@ -113,10 +113,10 @@ impl DynamicItems {
}

#[allow(clippy::too_many_arguments)]
pub fn push(
pub(crate) fn push(
&mut self,
ident: Ident,
abi: Abi,
abi: ClangAbi,
is_variadic: bool,
is_required: bool,
args: Vec<proc_macro2::TokenStream>,
Expand Down
46 changes: 28 additions & 18 deletions bindgen/codegen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ use crate::ir::derive::{
};
use crate::ir::dot;
use crate::ir::enum_ty::{Enum, EnumVariant, EnumVariantValue};
use crate::ir::function::{Abi, Function, FunctionKind, FunctionSig, Linkage};
use crate::ir::function::{
Abi, ClangAbi, Function, FunctionKind, FunctionSig, Linkage,
};
use crate::ir::int::IntKind;
use crate::ir::item::{IsOpaque, Item, ItemCanonicalName, ItemCanonicalPath};
use crate::ir::item_kind::ItemKind;
Expand Down Expand Up @@ -2474,9 +2476,13 @@ impl MethodCodegen for Method {
_ => panic!("How in the world?"),
};

let supported_abi = match signature.abi() {
Abi::ThisCall => ctx.options().rust_features().thiscall_abi,
Abi::Vectorcall => ctx.options().rust_features().vectorcall_abi,
let supported_abi = match signature.abi(ctx, Some(&*name)) {
ClangAbi::Known(Abi::ThisCall) => {
ctx.options().rust_features().thiscall_abi
}
ClangAbi::Known(Abi::Vectorcall) => {
ctx.options().rust_features().vectorcall_abi
}
_ => true,
};

Expand Down Expand Up @@ -3988,14 +3994,16 @@ impl TryToRustTy for FunctionSig {
// TODO: we might want to consider ignoring the reference return value.
let ret = utils::fnsig_return_ty(ctx, self);
let arguments = utils::fnsig_arguments(ctx, self);
let abi = self.abi();
let abi = self.abi(ctx, None);

match abi {
Abi::ThisCall if !ctx.options().rust_features().thiscall_abi => {
ClangAbi::Known(Abi::ThisCall)
if !ctx.options().rust_features().thiscall_abi =>
{
warn!("Skipping function with thiscall ABI that isn't supported by the configured Rust target");
Ok(proc_macro2::TokenStream::new())
}
Abi::Vectorcall
ClangAbi::Known(Abi::Vectorcall)
if !ctx.options().rust_features().vectorcall_abi =>
{
warn!("Skipping function with vectorcall ABI that isn't supported by the configured Rust target");
Expand Down Expand Up @@ -4099,22 +4107,24 @@ impl CodeGenerator for Function {
attributes.push(attributes::doc(comment));
}

let abi = match signature.abi() {
Abi::ThisCall if !ctx.options().rust_features().thiscall_abi => {
let abi = match signature.abi(ctx, Some(name)) {
ClangAbi::Known(Abi::ThisCall)
if !ctx.options().rust_features().thiscall_abi =>
{
warn!("Skipping function with thiscall ABI that isn't supported by the configured Rust target");
return None;
}
Abi::Vectorcall
ClangAbi::Known(Abi::Vectorcall)
if !ctx.options().rust_features().vectorcall_abi =>
{
warn!("Skipping function with vectorcall ABI that isn't supported by the configured Rust target");
return None;
}
Abi::Win64 if signature.is_variadic() => {
ClangAbi::Known(Abi::Win64) if signature.is_variadic() => {
warn!("Skipping variadic function with Win64 ABI that isn't supported");
return None;
}
Abi::Unknown(unknown_abi) => {
ClangAbi::Unknown(unknown_abi) => {
panic!(
"Invalid or unknown abi {:?} for function {:?} ({:?})",
unknown_abi, canonical_name, self
Expand Down Expand Up @@ -4512,7 +4522,7 @@ pub(crate) fn codegen(
pub mod utils {
use super::{error, ToRustTyOrOpaque};
use crate::ir::context::BindgenContext;
use crate::ir::function::{Abi, FunctionSig};
use crate::ir::function::{Abi, ClangAbi, FunctionSig};
use crate::ir::item::{Item, ItemCanonicalPath};
use crate::ir::ty::TypeKind;
use proc_macro2;
Expand Down Expand Up @@ -4973,10 +4983,10 @@ pub mod utils {
// Returns true if `canonical_name` will end up as `mangled_name` at the
// machine code level, i.e. after LLVM has applied any target specific
// mangling.
pub fn names_will_be_identical_after_mangling(
pub(crate) fn names_will_be_identical_after_mangling(
canonical_name: &str,
mangled_name: &str,
call_conv: Option<Abi>,
call_conv: Option<ClangAbi>,
) -> bool {
// If the mangled name and the canonical name are the same then no
// mangling can have happened between the two versions.
Expand All @@ -4989,13 +4999,13 @@ pub mod utils {
let mangled_name = mangled_name.as_bytes();

let (mangling_prefix, expect_suffix) = match call_conv {
Some(Abi::C) |
Some(ClangAbi::Known(Abi::C)) |
// None is the case for global variables
None => {
(b'_', false)
}
Some(Abi::Stdcall) => (b'_', true),
Some(Abi::Fastcall) => (b'@', true),
Some(ClangAbi::Known(Abi::Stdcall)) => (b'_', true),
Some(ClangAbi::Known(Abi::Fastcall)) => (b'@', true),

// This is something we don't recognize, stay on the safe side
// by emitting the `#[link_name]` attribute
Expand Down
Loading

0 comments on commit 9c32b46

Please sign in to comment.