Implement #[link_ordinal] attribute in the context of #[link(kind = "raw-dylib")].
This commit is contained in:
parent
60e70cc909
commit
142f6c0b07
20 changed files with 201 additions and 23 deletions
|
@ -163,13 +163,13 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
|
||||||
// All import names are Rust identifiers and therefore cannot contain \0 characters.
|
// All import names are Rust identifiers and therefore cannot contain \0 characters.
|
||||||
// FIXME: when support for #[link_name] implemented, ensure that import.name values don't
|
// FIXME: when support for #[link_name] implemented, ensure that import.name values don't
|
||||||
// have any \0 characters
|
// have any \0 characters
|
||||||
let import_name_vector: Vec<CString> = dll_imports
|
let import_name_and_ordinal_vector: Vec<(CString, Option<u16>)> = dll_imports
|
||||||
.iter()
|
.iter()
|
||||||
.map(|import: &DllImport| {
|
.map(|import: &DllImport| {
|
||||||
if self.config.sess.target.arch == "x86" {
|
if self.config.sess.target.arch == "x86" {
|
||||||
LlvmArchiveBuilder::i686_decorated_name(import)
|
(LlvmArchiveBuilder::i686_decorated_name(import), import.ordinal)
|
||||||
} else {
|
} else {
|
||||||
CString::new(import.name.to_string()).unwrap()
|
(CString::new(import.name.to_string()).unwrap(), import.ordinal)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
@ -184,9 +184,9 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
|
||||||
dll_imports.iter().map(|import| import.name.to_string()).collect::<Vec<_>>().join(", "),
|
dll_imports.iter().map(|import| import.name.to_string()).collect::<Vec<_>>().join(", "),
|
||||||
);
|
);
|
||||||
|
|
||||||
let ffi_exports: Vec<LLVMRustCOFFShortExport> = import_name_vector
|
let ffi_exports: Vec<LLVMRustCOFFShortExport> = import_name_and_ordinal_vector
|
||||||
.iter()
|
.iter()
|
||||||
.map(|name_z| LLVMRustCOFFShortExport::from_name(name_z.as_ptr()))
|
.map(|(name_z, ordinal)| LLVMRustCOFFShortExport::new(name_z.as_ptr(), *ordinal))
|
||||||
.collect();
|
.collect();
|
||||||
let result = unsafe {
|
let result = unsafe {
|
||||||
crate::llvm::LLVMRustWriteImportLibrary(
|
crate::llvm::LLVMRustWriteImportLibrary(
|
||||||
|
|
|
@ -34,11 +34,18 @@ pub enum LLVMRustResult {
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct LLVMRustCOFFShortExport {
|
pub struct LLVMRustCOFFShortExport {
|
||||||
pub name: *const c_char,
|
pub name: *const c_char,
|
||||||
|
pub ordinal_present: bool,
|
||||||
|
// value of `ordinal` only important when `ordinal_present` is true
|
||||||
|
pub ordinal: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LLVMRustCOFFShortExport {
|
impl LLVMRustCOFFShortExport {
|
||||||
pub fn from_name(name: *const c_char) -> LLVMRustCOFFShortExport {
|
pub fn new(name: *const c_char, ordinal: Option<u16>) -> LLVMRustCOFFShortExport {
|
||||||
LLVMRustCOFFShortExport { name }
|
LLVMRustCOFFShortExport {
|
||||||
|
name,
|
||||||
|
ordinal_present: ordinal.is_some(),
|
||||||
|
ordinal: ordinal.unwrap_or(0),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1749,10 +1749,11 @@ LLVMRustBuildMaxNum(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// This struct contains all necessary info about a symbol exported from a DLL.
|
// This struct contains all necessary info about a symbol exported from a DLL.
|
||||||
// At the moment, it's just the symbol's name, but we use a separate struct to
|
|
||||||
// make it easier to add other information like ordinal later.
|
|
||||||
struct LLVMRustCOFFShortExport {
|
struct LLVMRustCOFFShortExport {
|
||||||
const char* name;
|
const char* name;
|
||||||
|
bool ordinal_present;
|
||||||
|
// The value of `ordinal` is only meaningful if `ordinal_present` is true.
|
||||||
|
uint16_t ordinal;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Machine must be a COFF machine type, as defined in PE specs.
|
// Machine must be a COFF machine type, as defined in PE specs.
|
||||||
|
@ -1768,13 +1769,15 @@ extern "C" LLVMRustResult LLVMRustWriteImportLibrary(
|
||||||
ConvertedExports.reserve(NumExports);
|
ConvertedExports.reserve(NumExports);
|
||||||
|
|
||||||
for (size_t i = 0; i < NumExports; ++i) {
|
for (size_t i = 0; i < NumExports; ++i) {
|
||||||
|
bool ordinal_present = Exports[i].ordinal_present;
|
||||||
|
uint16_t ordinal = ordinal_present ? Exports[i].ordinal : 0;
|
||||||
ConvertedExports.push_back(llvm::object::COFFShortExport{
|
ConvertedExports.push_back(llvm::object::COFFShortExport{
|
||||||
Exports[i].name, // Name
|
Exports[i].name, // Name
|
||||||
std::string{}, // ExtName
|
std::string{}, // ExtName
|
||||||
std::string{}, // SymbolName
|
std::string{}, // SymbolName
|
||||||
std::string{}, // AliasTarget
|
std::string{}, // AliasTarget
|
||||||
0, // Ordinal
|
ordinal, // Ordinal
|
||||||
false, // Noname
|
ordinal_present, // Noname
|
||||||
false, // Data
|
false, // Data
|
||||||
false, // Private
|
false, // Private
|
||||||
false // Constant
|
false // Constant
|
||||||
|
|
|
@ -433,6 +433,12 @@ impl Collector<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
DllImport { name: item.ident.name, ordinal: None, calling_convention, span: item.span }
|
|
||||||
|
DllImport {
|
||||||
|
name: item.ident.name,
|
||||||
|
ordinal: self.tcx.codegen_fn_attrs(item.id.def_id).link_ordinal,
|
||||||
|
calling_convention,
|
||||||
|
span: item.span,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ pub struct CodegenFnAttrs {
|
||||||
/// imported function has in the dynamic library. Note that this must not
|
/// imported function has in the dynamic library. Note that this must not
|
||||||
/// be set when `link_name` is set. This is for foreign items with the
|
/// be set when `link_name` is set. This is for foreign items with the
|
||||||
/// "raw-dylib" kind.
|
/// "raw-dylib" kind.
|
||||||
pub link_ordinal: Option<usize>,
|
pub link_ordinal: Option<u16>,
|
||||||
/// The `#[target_feature(enable = "...")]` attribute and the enabled
|
/// The `#[target_feature(enable = "...")]` attribute and the enabled
|
||||||
/// features (only enabled features are supported right now).
|
/// features (only enabled features are supported right now).
|
||||||
pub target_features: Vec<Symbol>,
|
pub target_features: Vec<Symbol>,
|
||||||
|
|
|
@ -2858,6 +2858,14 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
|
||||||
} else if attr.has_name(sym::link_name) {
|
} else if attr.has_name(sym::link_name) {
|
||||||
codegen_fn_attrs.link_name = attr.value_str();
|
codegen_fn_attrs.link_name = attr.value_str();
|
||||||
} else if attr.has_name(sym::link_ordinal) {
|
} else if attr.has_name(sym::link_ordinal) {
|
||||||
|
if link_ordinal_span.is_some() {
|
||||||
|
tcx.sess
|
||||||
|
.struct_span_err(
|
||||||
|
attr.span,
|
||||||
|
"multiple `link_ordinal` attributes on a single definition",
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
}
|
||||||
link_ordinal_span = Some(attr.span);
|
link_ordinal_span = Some(attr.span);
|
||||||
if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) {
|
if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) {
|
||||||
codegen_fn_attrs.link_ordinal = ordinal;
|
codegen_fn_attrs.link_ordinal = ordinal;
|
||||||
|
@ -3153,22 +3161,41 @@ fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option<usize> {
|
fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option<u16> {
|
||||||
use rustc_ast::{Lit, LitIntType, LitKind};
|
use rustc_ast::{Lit, LitIntType, LitKind};
|
||||||
let meta_item_list = attr.meta_item_list();
|
let meta_item_list = attr.meta_item_list();
|
||||||
let meta_item_list: Option<&[ast::NestedMetaItem]> = meta_item_list.as_ref().map(Vec::as_ref);
|
let meta_item_list: Option<&[ast::NestedMetaItem]> = meta_item_list.as_ref().map(Vec::as_ref);
|
||||||
let sole_meta_list = match meta_item_list {
|
let sole_meta_list = match meta_item_list {
|
||||||
Some([item]) => item.literal(),
|
Some([item]) => item.literal(),
|
||||||
|
Some(_) => {
|
||||||
|
tcx.sess
|
||||||
|
.struct_span_err(attr.span, "incorrect number of arguments to `#[link_ordinal]`")
|
||||||
|
.note("the attribute requires exactly one argument")
|
||||||
|
.emit();
|
||||||
|
return None;
|
||||||
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
if let Some(Lit { kind: LitKind::Int(ordinal, LitIntType::Unsuffixed), .. }) = sole_meta_list {
|
if let Some(Lit { kind: LitKind::Int(ordinal, LitIntType::Unsuffixed), .. }) = sole_meta_list {
|
||||||
if *ordinal <= usize::MAX as u128 {
|
// According to the table at https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#import-header,
|
||||||
Some(*ordinal as usize)
|
// the ordinal must fit into 16 bits. Similarly, the Ordinal field in COFFShortExport (defined
|
||||||
|
// in llvm/include/llvm/Object/COFFImportFile.h), which we use to communicate import information
|
||||||
|
// to LLVM for `#[link(kind = "raw-dylib"_])`, is also defined to be uint16_t.
|
||||||
|
//
|
||||||
|
// FIXME: should we allow an ordinal of 0? The MSVC toolchain has inconsistent support for this:
|
||||||
|
// both LINK.EXE and LIB.EXE signal errors and abort when given a .DEF file that specifies
|
||||||
|
// a zero ordinal. However, llvm-dlltool is perfectly happy to generate an import library
|
||||||
|
// for such a .DEF file, and MSVC's LINK.EXE is also perfectly happy to consume an import
|
||||||
|
// library produced by LLVM with an ordinal of 0, and it generates an .EXE. (I don't know yet
|
||||||
|
// if the resulting EXE runs, as I haven't yet built the necessary DLL -- see earlier comment
|
||||||
|
// about LINK.EXE failing.)
|
||||||
|
if *ordinal <= u16::MAX as u128 {
|
||||||
|
Some(*ordinal as u16)
|
||||||
} else {
|
} else {
|
||||||
let msg = format!("ordinal value in `link_ordinal` is too large: `{}`", &ordinal);
|
let msg = format!("ordinal value in `link_ordinal` is too large: `{}`", &ordinal);
|
||||||
tcx.sess
|
tcx.sess
|
||||||
.struct_span_err(attr.span, &msg)
|
.struct_span_err(attr.span, &msg)
|
||||||
.note("the value may not exceed `usize::MAX`")
|
.note("the value may not exceed `u16::MAX`")
|
||||||
.emit();
|
.emit();
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
18
src/test/run-make/raw-dylib-link-ordinal/Makefile
Normal file
18
src/test/run-make/raw-dylib-link-ordinal/Makefile
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# Test the behavior of #[link(.., kind = "raw-dylib")] and #[link_ordinal] on windows-msvc
|
||||||
|
|
||||||
|
# only-windows-msvc
|
||||||
|
|
||||||
|
-include ../../run-make-fulldeps/tools.mk
|
||||||
|
|
||||||
|
all:
|
||||||
|
$(call COMPILE_OBJ,"$(TMPDIR)"/exporter.obj,exporter.c)
|
||||||
|
$(CC) "$(TMPDIR)"/exporter.obj exporter.def -link -dll -out:"$(TMPDIR)"/exporter.dll
|
||||||
|
$(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs
|
||||||
|
$(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
|
||||||
|
"$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt
|
||||||
|
|
||||||
|
ifdef RUSTC_BLESS_TEST
|
||||||
|
cp "$(TMPDIR)"/output.txt output.txt
|
||||||
|
else
|
||||||
|
$(DIFF) output.txt "$(TMPDIR)"/output.txt
|
||||||
|
endif
|
5
src/test/run-make/raw-dylib-link-ordinal/driver.rs
Normal file
5
src/test/run-make/raw-dylib-link-ordinal/driver.rs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
extern crate raw_dylib_test;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
raw_dylib_test::library_function();
|
||||||
|
}
|
5
src/test/run-make/raw-dylib-link-ordinal/exporter.c
Normal file
5
src/test/run-make/raw-dylib-link-ordinal/exporter.c
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
void exported_function() {
|
||||||
|
printf("exported_function\n");
|
||||||
|
}
|
3
src/test/run-make/raw-dylib-link-ordinal/exporter.def
Normal file
3
src/test/run-make/raw-dylib-link-ordinal/exporter.def
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
LIBRARY exporter
|
||||||
|
EXPORTS
|
||||||
|
exported_function @13 NONAME
|
13
src/test/run-make/raw-dylib-link-ordinal/lib.rs
Normal file
13
src/test/run-make/raw-dylib-link-ordinal/lib.rs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#![feature(raw_dylib)]
|
||||||
|
|
||||||
|
#[link(name = "exporter", kind = "raw-dylib")]
|
||||||
|
extern {
|
||||||
|
#[link_ordinal(13)]
|
||||||
|
fn imported_function();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn library_function() {
|
||||||
|
unsafe {
|
||||||
|
imported_function();
|
||||||
|
}
|
||||||
|
}
|
1
src/test/run-make/raw-dylib-link-ordinal/output.txt
Normal file
1
src/test/run-make/raw-dylib-link-ordinal/output.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
exported_function
|
|
@ -0,0 +1,11 @@
|
||||||
|
#![feature(raw_dylib)]
|
||||||
|
//~^ WARN the feature `raw_dylib` is incomplete
|
||||||
|
|
||||||
|
#[link(name = "foo")]
|
||||||
|
extern "C" {
|
||||||
|
#[link_ordinal()]
|
||||||
|
//~^ ERROR incorrect number of arguments to `#[link_ordinal]`
|
||||||
|
fn foo();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,19 @@
|
||||||
|
warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||||
|
--> $DIR/link-ordinal-missing-argument.rs:1:12
|
||||||
|
|
|
||||||
|
LL | #![feature(raw_dylib)]
|
||||||
|
| ^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `#[warn(incomplete_features)]` on by default
|
||||||
|
= note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
|
||||||
|
|
||||||
|
error: incorrect number of arguments to `#[link_ordinal]`
|
||||||
|
--> $DIR/link-ordinal-missing-argument.rs:6:5
|
||||||
|
|
|
||||||
|
LL | #[link_ordinal()]
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: the attribute requires exactly one argument
|
||||||
|
|
||||||
|
error: aborting due to previous error; 1 warning emitted
|
||||||
|
|
13
src/test/ui/rfc-2627-raw-dylib/link-ordinal-multiple.rs
Normal file
13
src/test/ui/rfc-2627-raw-dylib/link-ordinal-multiple.rs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
// only-windows-msvc
|
||||||
|
#![feature(raw_dylib)]
|
||||||
|
//~^ WARN the feature `raw_dylib` is incomplete
|
||||||
|
|
||||||
|
#[link(name = "foo", kind = "raw-dylib")]
|
||||||
|
extern "C" {
|
||||||
|
#[link_ordinal(1)]
|
||||||
|
#[link_ordinal(2)]
|
||||||
|
//~^ ERROR multiple `link_ordinal` attributes on a single definition
|
||||||
|
fn foo();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
17
src/test/ui/rfc-2627-raw-dylib/link-ordinal-multiple.stderr
Normal file
17
src/test/ui/rfc-2627-raw-dylib/link-ordinal-multiple.stderr
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||||
|
--> $DIR/link-ordinal-multiple.rs:2:12
|
||||||
|
|
|
||||||
|
LL | #![feature(raw_dylib)]
|
||||||
|
| ^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `#[warn(incomplete_features)]` on by default
|
||||||
|
= note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
|
||||||
|
|
||||||
|
error: multiple `link_ordinal` attributes on a single definition
|
||||||
|
--> $DIR/link-ordinal-multiple.rs:8:5
|
||||||
|
|
|
||||||
|
LL | #[link_ordinal(2)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to previous error; 1 warning emitted
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
|
|
||||||
#[link(name = "foo")]
|
#[link(name = "foo")]
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#[link_ordinal(18446744073709551616)]
|
#[link_ordinal(72436)]
|
||||||
//~^ ERROR ordinal value in `link_ordinal` is too large: `18446744073709551616`
|
//~^ ERROR ordinal value in `link_ordinal` is too large: `72436`
|
||||||
fn foo();
|
fn foo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,13 +7,13 @@ LL | #![feature(raw_dylib)]
|
||||||
= note: `#[warn(incomplete_features)]` on by default
|
= note: `#[warn(incomplete_features)]` on by default
|
||||||
= note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
|
= note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
|
||||||
|
|
||||||
error: ordinal value in `link_ordinal` is too large: `18446744073709551616`
|
error: ordinal value in `link_ordinal` is too large: `72436`
|
||||||
--> $DIR/link-ordinal-too-large.rs:6:5
|
--> $DIR/link-ordinal-too-large.rs:6:5
|
||||||
|
|
|
|
||||||
LL | #[link_ordinal(18446744073709551616)]
|
LL | #[link_ordinal(72436)]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: the value may not exceed `usize::MAX`
|
= note: the value may not exceed `u16::MAX`
|
||||||
|
|
||||||
error: aborting due to previous error; 1 warning emitted
|
error: aborting due to previous error; 1 warning emitted
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
#![feature(raw_dylib)]
|
||||||
|
//~^ WARN the feature `raw_dylib` is incomplete
|
||||||
|
|
||||||
|
#[link(name = "foo")]
|
||||||
|
extern "C" {
|
||||||
|
#[link_ordinal(3, 4)]
|
||||||
|
//~^ ERROR incorrect number of arguments to `#[link_ordinal]`
|
||||||
|
fn foo();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,19 @@
|
||||||
|
warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||||
|
--> $DIR/link-ordinal-too-many-arguments.rs:1:12
|
||||||
|
|
|
||||||
|
LL | #![feature(raw_dylib)]
|
||||||
|
| ^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `#[warn(incomplete_features)]` on by default
|
||||||
|
= note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
|
||||||
|
|
||||||
|
error: incorrect number of arguments to `#[link_ordinal]`
|
||||||
|
--> $DIR/link-ordinal-too-many-arguments.rs:6:5
|
||||||
|
|
|
||||||
|
LL | #[link_ordinal(3, 4)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: the attribute requires exactly one argument
|
||||||
|
|
||||||
|
error: aborting due to previous error; 1 warning emitted
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue