Skip to content

Commit 9c32b46

Browse files
authored
Add the --override-abi option (#2329)
* 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
1 parent a673a6b commit 9c32b46

File tree

8 files changed

+190
-76
lines changed

8 files changed

+190
-76
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,8 @@
148148
# Unreleased
149149

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

152154
## Changed
153155

bindgen-cli/options.rs

+18
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,12 @@ where
568568
Arg::new("merge-extern-blocks")
569569
.long("merge-extern-blocks")
570570
.help("Deduplicates extern blocks."),
571+
Arg::new("override-abi")
572+
.long("override-abi")
573+
.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.")
574+
.value_name("override")
575+
.multiple_occurrences(true)
576+
.number_of_values(1),
571577
Arg::new("V")
572578
.long("version")
573579
.help("Prints the version, and exits"),
@@ -1088,5 +1094,17 @@ where
10881094
builder = builder.merge_extern_blocks(true);
10891095
}
10901096

1097+
if let Some(abi_overrides) = matches.values_of("override-abi") {
1098+
for abi_override in abi_overrides {
1099+
let (regex, abi_str) = abi_override
1100+
.rsplit_once("=")
1101+
.expect("Invalid ABI override: Missing `=`");
1102+
let abi = abi_str
1103+
.parse()
1104+
.unwrap_or_else(|err| panic!("Invalid ABI override: {}", err));
1105+
builder = builder.override_abi(abi, regex);
1106+
}
1107+
}
1108+
10911109
Ok((builder, output, verbose))
10921110
}

bindgen-tests/tests/expectations/tests/abi-override.rs

+16
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// bindgen-flags: --override-abi=foo=fastcall --override-abi=bar=stdcall
2+
3+
void foo();
4+
void bar();
5+
void baz();

bindgen/codegen/dyngen.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::codegen;
2-
use crate::ir::function::Abi;
2+
use crate::ir::function::ClangAbi;
33
use proc_macro2::Ident;
44

55
/// Used to build the output tokens for dynamic bindings.
@@ -113,10 +113,10 @@ impl DynamicItems {
113113
}
114114

115115
#[allow(clippy::too_many_arguments)]
116-
pub fn push(
116+
pub(crate) fn push(
117117
&mut self,
118118
ident: Ident,
119-
abi: Abi,
119+
abi: ClangAbi,
120120
is_variadic: bool,
121121
is_required: bool,
122122
args: Vec<proc_macro2::TokenStream>,

bindgen/codegen/mod.rs

+28-18
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ use crate::ir::derive::{
3232
};
3333
use crate::ir::dot;
3434
use crate::ir::enum_ty::{Enum, EnumVariant, EnumVariantValue};
35-
use crate::ir::function::{Abi, Function, FunctionKind, FunctionSig, Linkage};
35+
use crate::ir::function::{
36+
Abi, ClangAbi, Function, FunctionKind, FunctionSig, Linkage,
37+
};
3638
use crate::ir::int::IntKind;
3739
use crate::ir::item::{IsOpaque, Item, ItemCanonicalName, ItemCanonicalPath};
3840
use crate::ir::item_kind::ItemKind;
@@ -2474,9 +2476,13 @@ impl MethodCodegen for Method {
24742476
_ => panic!("How in the world?"),
24752477
};
24762478

2477-
let supported_abi = match signature.abi() {
2478-
Abi::ThisCall => ctx.options().rust_features().thiscall_abi,
2479-
Abi::Vectorcall => ctx.options().rust_features().vectorcall_abi,
2479+
let supported_abi = match signature.abi(ctx, Some(&*name)) {
2480+
ClangAbi::Known(Abi::ThisCall) => {
2481+
ctx.options().rust_features().thiscall_abi
2482+
}
2483+
ClangAbi::Known(Abi::Vectorcall) => {
2484+
ctx.options().rust_features().vectorcall_abi
2485+
}
24802486
_ => true,
24812487
};
24822488

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

39933999
match abi {
3994-
Abi::ThisCall if !ctx.options().rust_features().thiscall_abi => {
4000+
ClangAbi::Known(Abi::ThisCall)
4001+
if !ctx.options().rust_features().thiscall_abi =>
4002+
{
39954003
warn!("Skipping function with thiscall ABI that isn't supported by the configured Rust target");
39964004
Ok(proc_macro2::TokenStream::new())
39974005
}
3998-
Abi::Vectorcall
4006+
ClangAbi::Known(Abi::Vectorcall)
39994007
if !ctx.options().rust_features().vectorcall_abi =>
40004008
{
40014009
warn!("Skipping function with vectorcall ABI that isn't supported by the configured Rust target");
@@ -4099,22 +4107,24 @@ impl CodeGenerator for Function {
40994107
attributes.push(attributes::doc(comment));
41004108
}
41014109

4102-
let abi = match signature.abi() {
4103-
Abi::ThisCall if !ctx.options().rust_features().thiscall_abi => {
4110+
let abi = match signature.abi(ctx, Some(name)) {
4111+
ClangAbi::Known(Abi::ThisCall)
4112+
if !ctx.options().rust_features().thiscall_abi =>
4113+
{
41044114
warn!("Skipping function with thiscall ABI that isn't supported by the configured Rust target");
41054115
return None;
41064116
}
4107-
Abi::Vectorcall
4117+
ClangAbi::Known(Abi::Vectorcall)
41084118
if !ctx.options().rust_features().vectorcall_abi =>
41094119
{
41104120
warn!("Skipping function with vectorcall ABI that isn't supported by the configured Rust target");
41114121
return None;
41124122
}
4113-
Abi::Win64 if signature.is_variadic() => {
4123+
ClangAbi::Known(Abi::Win64) if signature.is_variadic() => {
41144124
warn!("Skipping variadic function with Win64 ABI that isn't supported");
41154125
return None;
41164126
}
4117-
Abi::Unknown(unknown_abi) => {
4127+
ClangAbi::Unknown(unknown_abi) => {
41184128
panic!(
41194129
"Invalid or unknown abi {:?} for function {:?} ({:?})",
41204130
unknown_abi, canonical_name, self
@@ -4512,7 +4522,7 @@ pub(crate) fn codegen(
45124522
pub mod utils {
45134523
use super::{error, ToRustTyOrOpaque};
45144524
use crate::ir::context::BindgenContext;
4515-
use crate::ir::function::{Abi, FunctionSig};
4525+
use crate::ir::function::{Abi, ClangAbi, FunctionSig};
45164526
use crate::ir::item::{Item, ItemCanonicalPath};
45174527
use crate::ir::ty::TypeKind;
45184528
use proc_macro2;
@@ -4973,10 +4983,10 @@ pub mod utils {
49734983
// Returns true if `canonical_name` will end up as `mangled_name` at the
49744984
// machine code level, i.e. after LLVM has applied any target specific
49754985
// mangling.
4976-
pub fn names_will_be_identical_after_mangling(
4986+
pub(crate) fn names_will_be_identical_after_mangling(
49774987
canonical_name: &str,
49784988
mangled_name: &str,
4979-
call_conv: Option<Abi>,
4989+
call_conv: Option<ClangAbi>,
49804990
) -> bool {
49814991
// If the mangled name and the canonical name are the same then no
49824992
// mangling can have happened between the two versions.
@@ -4989,13 +4999,13 @@ pub mod utils {
49894999
let mangled_name = mangled_name.as_bytes();
49905000

49915001
let (mangling_prefix, expect_suffix) = match call_conv {
4992-
Some(Abi::C) |
5002+
Some(ClangAbi::Known(Abi::C)) |
49935003
// None is the case for global variables
49945004
None => {
49955005
(b'_', false)
49965006
}
4997-
Some(Abi::Stdcall) => (b'_', true),
4998-
Some(Abi::Fastcall) => (b'@', true),
5007+
Some(ClangAbi::Known(Abi::Stdcall)) => (b'_', true),
5008+
Some(ClangAbi::Known(Abi::Fastcall)) => (b'@', true),
49995009

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

0 commit comments

Comments
 (0)