mirror of
https://git.proxmox.com/git/perlmod
synced 2025-10-04 09:08:06 +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 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 {
|
||||
@ -43,7 +47,7 @@ sub help {
|
||||
print {$fd} "mandatory OPTIONS are:\n";
|
||||
for my $o (sort keys %$opts) {
|
||||
my ($arg, $desc) = $opts->{$o}->@*;
|
||||
my $p = "--$o=$arg";
|
||||
my $p = defined($arg) ? "--$o=$arg" : "--$o";
|
||||
printf {$fd} " %20s %s\n", $p, $desc;
|
||||
}
|
||||
}
|
||||
@ -74,6 +78,13 @@ ARGPARSE: while (@ARGV) {
|
||||
} else {
|
||||
next;
|
||||
};
|
||||
|
||||
if (!defined($opts->{$o}->[0])) {
|
||||
unshift @ARGV, $arg;
|
||||
$params->{$o} = 1;
|
||||
next ARGPARSE;
|
||||
}
|
||||
|
||||
die "--$o requires an argument\n" if !defined($arg);
|
||||
if (ref($params->{$o}) eq 'ARRAY') {
|
||||
push $params->{$o}->@*, $arg;
|
||||
@ -99,7 +110,8 @@ my $lib_prefix = $params->{'lib-prefix'}
|
||||
or die "missing --lib-prefix parameter\n";
|
||||
my $lib = $params->{'lib'}
|
||||
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 $extra_code = '';
|
||||
for my $file ($params->{'include-file'}->@*) {
|
||||
@ -108,6 +120,7 @@ for my $file ($params->{'include-file'}->@*) {
|
||||
die "error reading '$file': $!\n" if !defined($more);
|
||||
$extra_code .= $more;
|
||||
}
|
||||
my $from_notes = $params->{'from-notes'};
|
||||
|
||||
sub pkg2file {
|
||||
return ($_[0] =~ s@::@/@gr) . ".pm";
|
||||
@ -225,6 +238,29 @@ if ($lib ne '-') {
|
||||
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) {
|
||||
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_ident = Ident::new(&bootstrap_name, Span::call_site());
|
||||
|
||||
@ -120,7 +123,13 @@ impl Package {
|
||||
pub extern "C" fn #bootstrap_ident(
|
||||
_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();
|
||||
|
||||
ONCE.call_once(|| {
|
||||
unsafe {
|
||||
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()).
|
||||
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