mirror of
https://git.proxmox.com/git/perlmod
synced 2025-10-04 19:48:14 +00:00
macro: create .notes.perlmod.package section in libraries
So all the macro-supported packages can be listed in the ELF file. This way all the available packages in a library can be viewed with `readelf -W -n libfoo.so`. In the future we can also embed metadata in there. Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
parent
ca64bc9fdf
commit
057f71a473
@ -34,6 +34,10 @@ my $opts = {
|
|||||||
'PATH',
|
'PATH',
|
||||||
"Path to additional perl code to include in the package after the 'use' statements",
|
"Path to additional perl code to include in the package after the 'use' statements",
|
||||||
],
|
],
|
||||||
|
'from-notes' => [
|
||||||
|
undef,
|
||||||
|
"Read the package list from ELF notes sections",
|
||||||
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
sub help {
|
sub help {
|
||||||
@ -43,7 +47,7 @@ sub help {
|
|||||||
print {$fd} "mandatory OPTIONS are:\n";
|
print {$fd} "mandatory OPTIONS are:\n";
|
||||||
for my $o (sort keys %$opts) {
|
for my $o (sort keys %$opts) {
|
||||||
my ($arg, $desc) = $opts->{$o}->@*;
|
my ($arg, $desc) = $opts->{$o}->@*;
|
||||||
my $p = "--$o=$arg";
|
my $p = defined($arg) ? "--$o=$arg" : "--$o";
|
||||||
printf {$fd} " %20s %s\n", $p, $desc;
|
printf {$fd} " %20s %s\n", $p, $desc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -74,6 +78,13 @@ ARGPARSE: while (@ARGV) {
|
|||||||
} else {
|
} else {
|
||||||
next;
|
next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!defined($opts->{$o}->[0])) {
|
||||||
|
unshift @ARGV, $arg;
|
||||||
|
$params->{$o} = 1;
|
||||||
|
next ARGPARSE;
|
||||||
|
}
|
||||||
|
|
||||||
die "--$o requires an argument\n" if !defined($arg);
|
die "--$o requires an argument\n" if !defined($arg);
|
||||||
if (ref($params->{$o}) eq 'ARRAY') {
|
if (ref($params->{$o}) eq 'ARRAY') {
|
||||||
push $params->{$o}->@*, $arg;
|
push $params->{$o}->@*, $arg;
|
||||||
@ -99,7 +110,8 @@ my $lib_prefix = $params->{'lib-prefix'}
|
|||||||
or die "missing --lib-prefix parameter\n";
|
or die "missing --lib-prefix parameter\n";
|
||||||
my $lib = $params->{'lib'}
|
my $lib = $params->{'lib'}
|
||||||
or die "missing --lib parameter\n";
|
or die "missing --lib parameter\n";
|
||||||
my $lib_tag = $params->{'lib-tag'};
|
my $lib_tag = $params->{'lib-tag'}
|
||||||
|
or die "missing --lib-tag parameter\n";
|
||||||
my $debug_libpath = $params->{'debug-libpath'} // '';
|
my $debug_libpath = $params->{'debug-libpath'} // '';
|
||||||
my $extra_code = '';
|
my $extra_code = '';
|
||||||
for my $file ($params->{'include-file'}->@*) {
|
for my $file ($params->{'include-file'}->@*) {
|
||||||
@ -108,6 +120,7 @@ for my $file ($params->{'include-file'}->@*) {
|
|||||||
die "error reading '$file': $!\n" if !defined($more);
|
die "error reading '$file': $!\n" if !defined($more);
|
||||||
$extra_code .= $more;
|
$extra_code .= $more;
|
||||||
}
|
}
|
||||||
|
my $from_notes = $params->{'from-notes'};
|
||||||
|
|
||||||
sub pkg2file {
|
sub pkg2file {
|
||||||
return ($_[0] =~ s@::@/@gr) . ".pm";
|
return ($_[0] =~ s@::@/@gr) . ".pm";
|
||||||
@ -225,6 +238,29 @@ if ($lib ne '-') {
|
|||||||
close($fh);
|
close($fh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($from_notes) {
|
||||||
|
die "missing library file to read packages from\n" if !@ARGV;
|
||||||
|
die "--from-notes requires exactly one library\n" if @ARGV > 1;
|
||||||
|
|
||||||
|
open my $fh, '<', $ARGV[0] or die "failed to open $ARGV[0] for reading: $!\n";
|
||||||
|
my $fd = fileno($fh);
|
||||||
|
my $data = `objcopy -O binary --only-section .note.perlmod.package $ARGV[0] /dev/stdout`;
|
||||||
|
close($fh);
|
||||||
|
|
||||||
|
my @packages;
|
||||||
|
while (length($data)) {
|
||||||
|
my ($name_size, $desc_size, $ty) = unpack('LLL', substr($data, 0, 3*4, ''));
|
||||||
|
die "unexpected description in package note - incompatible perlmod version?\n"
|
||||||
|
if $desc_size;
|
||||||
|
my $name = substr($data, 0, $name_size, '');
|
||||||
|
my $desc = substr($data, 0, $desc_size, '');
|
||||||
|
print("Found package '$name'\n");
|
||||||
|
push @packages, $name;
|
||||||
|
}
|
||||||
|
die "trailing data in notes section\n" if length($data);
|
||||||
|
@ARGV = @packages;
|
||||||
|
}
|
||||||
|
|
||||||
for my $package (@ARGV) {
|
for my $package (@ARGV) {
|
||||||
my $path = ($package =~ s@::@/@gr) . ".pm";
|
my $path = ($package =~ s@::@/@gr) . ".pm";
|
||||||
|
|
||||||
|
@ -107,6 +107,9 @@ impl Package {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let package_name_bytes =
|
||||||
|
syn::LitByteStr::new(self.attrs.package_name.as_bytes(), Span::call_site());
|
||||||
|
let package_name_len = self.attrs.package_name.len();
|
||||||
let bootstrap_name = format!("boot_{}", self.attrs.package_name).replace("::", "__");
|
let bootstrap_name = format!("boot_{}", self.attrs.package_name).replace("::", "__");
|
||||||
let bootstrap_ident = Ident::new(&bootstrap_name, Span::call_site());
|
let bootstrap_ident = Ident::new(&bootstrap_name, Span::call_site());
|
||||||
|
|
||||||
@ -120,7 +123,13 @@ impl Package {
|
|||||||
pub extern "C" fn #bootstrap_ident(
|
pub extern "C" fn #bootstrap_ident(
|
||||||
_cv: Option<&::perlmod::ffi::CV>,
|
_cv: Option<&::perlmod::ffi::CV>,
|
||||||
) {
|
) {
|
||||||
|
#[used]
|
||||||
|
#[link_section = ".note.perlmod.package"]
|
||||||
|
static PACKAGE_ENTRY: ::perlmod::__private__::ElfNote<{#package_name_len}> =
|
||||||
|
::perlmod::__private__::ElfNote::new_package(*#package_name_bytes);
|
||||||
|
|
||||||
static ONCE: ::std::sync::Once = ::std::sync::Once::new();
|
static ONCE: ::std::sync::Once = ::std::sync::Once::new();
|
||||||
|
|
||||||
ONCE.call_once(|| {
|
ONCE.call_once(|| {
|
||||||
unsafe {
|
unsafe {
|
||||||
use ::perlmod::ffi::RSPL_newXS_flags;
|
use ::perlmod::ffi::RSPL_newXS_flags;
|
||||||
|
32
perlmod/src/elf_notes.rs
Normal file
32
perlmod/src/elf_notes.rs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
//! The `#[package]` macro stores package lists in ELF file note sections.
|
||||||
|
//! This is the implementation for this.
|
||||||
|
//!
|
||||||
|
//! This is private and not meant to be a public API.
|
||||||
|
|
||||||
|
/*
|
||||||
|
#[repr(C, packed)]
|
||||||
|
pub struct Info {
|
||||||
|
extra stuff
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#[repr(C, packed)]
|
||||||
|
pub struct ElfNote<const N: usize> {
|
||||||
|
pub name_size: u32,
|
||||||
|
pub desc_size: u32,
|
||||||
|
pub ty: u32,
|
||||||
|
pub name: [u8; N],
|
||||||
|
//pub desc: Info,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const N: usize> ElfNote<{ N }> {
|
||||||
|
pub const fn new_package(name: [u8; N]) -> Self {
|
||||||
|
Self {
|
||||||
|
name_size: N as u32,
|
||||||
|
desc_size: 0, // size_of::<Info>()
|
||||||
|
ty: 0,
|
||||||
|
name,
|
||||||
|
//desc: Info::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -113,3 +113,12 @@ pub use perlmod_macro::package;
|
|||||||
///
|
///
|
||||||
/// For an example on making blessed objects, see [`Value::bless_box`](Value::bless_box()).
|
/// For an example on making blessed objects, see [`Value::bless_box`](Value::bless_box()).
|
||||||
pub use perlmod_macro::export;
|
pub use perlmod_macro::export;
|
||||||
|
|
||||||
|
mod elf_notes;
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub mod __private__ {
|
||||||
|
//! This is private and not meant to be a public API and thus semver exempt.
|
||||||
|
|
||||||
|
pub use super::elf_notes::ElfNote;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user