If you're ever dealing with C Binary API's from Perl Code, via the syscall
, ioctl
, or fcntl
functions, you need to know how to construct memory in a C Compatible way.
For instance, if you were ever dealing with some function that expected a timespec
, you'd look into /usr/include/time.h
and find:
struct timespec
{
__time_t tv_sec; /* Seconds. */
__syscall_slong_t tv_nsec; /* Nanoseconds. */
};
You do a dance with cpp
to find what that really means:
cpp -E /usr/include/time.h -o /dev/stdout | grep __time_t
# typedef long int __time_t;
cpp -E /usr/include/time.h -o /dev/stdout | grep __syscall_slong_t
# typedef long int __syscall_slong_t
So its a (signed) int
echo 'void main(){ printf("%#lx\n", sizeof(__syscall_slong_t)); }' |
gcc -x c -include stdio.h -include time.h - -o /tmp/a.out && /tmp/a.out
# 0x8
And it takes 8 bytes. So 64bit signed int. And I'm on a 64Bit Processor. =)
Perldoc pack
says
q A signed quad (64-bit) value.
So to pack a timespec:
sub packtime {
my ( $config ) = @_;
return pack 'qq', @{$config}{qw( tv_sec tv_nsec )};
}
And to unpack a timespec:
sub unpacktime {
my ( $buf ) = @_;
my $out = {};
@{$out}{qw( tv_sec tv_nsec )} = unpack 'qq', $buf;
return $out;
}
Now you can just use those functions instead.
my $timespec = packtime({ tv_sec => 0, tv_nsec => 0 });
syscall( ..., $timespec ); # some syscall that reads timespec
later ...
syscall( ..., $timespec ); # some syscall that writes timespec
print Dumper( unpacktime( $timespec ));