Tuesday, April 14, 2009

Compiling Perl Into Binary Code On Linux And Unix. Cool, But...

Hey there,

Since as long back as I can remember, the Perl compiler has always been a vague, yet distant objective. Something that, when I was really into it, wasn't fully supported and didn't work unless you rewrote it yourself (which kind of ran contrary to the reason you were using Perl in the first place: To get complicated tasks taken care of quickly!)

Over the years, I've seen different front-ends come and go (a few of them which looked pretty slick), but I never bothered to check any of them out to a great degree. If I absolutely "had" to write something in "C," then I would. Otherwise, I'd go with Perl. Actually, my coding philosophy is a bit more pliable. Basically, given that I've been monkeying around with Unix and Linux (for pay) for 13 years or so, I tend to go with whatever is easiest, most reliable and most portable depending upon the task at hand. If it can be written in a "find" statement, that's good enough for me. Shell script, Sed and Awk (which usually end up in a Shell script), tcl, tk, expect, Perl, Python, C; whatever is the simplest way to resolve a problem and not kill my machines or compromise security to a great degree; that's what I go with. I see no point in writing a Perl script to open up a file descriptor to read STDIN, parse that and spit out lines containing the word "hi," like in this example:

#!/usr/bin/perl

# perl.pl - A complete waste of time ;)

open(FILE, "<myfile.txt");
@file=<FILE>;
close(FILE);

foreach $x (@file) {
print $x if ( $x =~ /hi/ );
}


host # ./perl.pl
hi there how are you?
Say hi to the mrs. for me


When simply typing (or making this into a one-line shell script):

host # grep hi myfile.txt
hi there how are you?
Say hi to the mrs. for me


will get me the exact same results. Admittedly, my Perl script above was a bit bloated, but the excess goes toward the point I'm making. At least I hope it does ;)

I came across an interesting product (Read: Not Free) called perl2exe that caught my attention since it can compile code for different OS's (derived from your original Perl script) and (after testing), actually works quite well. You can check it out for a free 30 day trial, although you should be aware that all of your generated code will have an advertisement tacked on the end and a 2 second delay. It'll also help you to know (if you want to check it out) that you need to download all the different OS packages (not just the one for the OS on which you're going to install) if you want to use the cross-platform code generation feature. It will compile code for Linux on a Unix box, but you have to download both the Linux and Unix distro gzipp'ed tarballs in order to do this. I'm not sure why. It may be just be another pain-in-the-arse designed to convince you to buy; but I am by no means, and in no way, shape or form, suggesting that you do so. And I'll tell you why...

Although this is one of the nicest packages, for compiling Perl scripts into executable binary code, that I've come across in a while (ease of use, etc) it still fails to address the one "major" flaw of all Perl-To-Binary conversion tools on the market. When you compile your Perl Script, you've lost all the flexibility you began using Perl for in the first place! No more inline editing for you ;)

For instance, a while back, we did a post on getting the year from Solaris' wtmpx file. Taking that Perl script and converting it to binary was a snap, like so:

host # time perl2exe -o rip_wtmpx rip_wtmpx.pl
Perl2Exe V9.100 Copyright (c) 1997-2008 IndigoSTAR Software

This is an evaluation version of Perl2Exe, which may be used for 30 days.
For more information see the attached pxman.htm file,
or visit http://www.indigostar.com

Converting 'rip_wtmpx.pl' to rip_wtmpx

real 0m0.506s
user 0m0.382s
sys 0m0.102s


Done in about a half a second. And, much to my amazement, it worked perfectly:

host # ./rip_wtmpx
PROCESSING WTMPX FILE FOR CROSS-CHECKING: .....
PROCESSED 2393 ENTRIES

root Thu Nov 6 13:42:07 2008
root Thu Nov 6 13:48:00 2008
root Thu Nov 6 13:51:58 2008
root Thu Nov 6 13:54:12 2008
root Thu Nov 6 14:38:20 2008
root Thu Nov 6 14:39:52 2008
root Thu Nov 6 14:39:54 2008
...


Which is the same result I get from running the Perl script directly (The whole point of it was to get the "year" from wtmpx, since the "last" command, and others like it, don't seem to want to give out that information, even though it's in the wtmp/utmp struct and proves very useful if you don't rotate your logs every year like I obviously don't ;)

But, then, you may recall that we followed up that post with a post on how to get the year from lastlog on Linux since Linux's implementation of the wtmp(x) struct had a totally different "pack" template than the one used on Solaris. I was getting around this by coding a mixture of both scripts and having it evaluate the host OS and act accordingly. Even so, for the odd machine (or new OS implementation we rolled out) I'd have to make slight tweaks. And that (although it's a pitiful example, I know ;) is where the whole "convenience" of binary Perl falls apart. Now, everytime I want to make a simple change (in this extremely simple example) I have to update my Perl script, regenerate binary code from it, for all the OS's required, and then redistributed all of that. The alternative, using just Perl, would be to modify the Perl script and redistribute the one version everywhere.

True, in this instance, there doesn't seem to be that much difference (just multiply it by a larger number of machines on your server farm and it gets worse ;), but the "convenience" really makes a difference when you find yourself on a machine that's got some weird kink in it. If you're using a straight-up Perl script, you can just edit it slightly to adjust for however fugged-up that particular box is. You don't have to maintain a separate binary. Odds are, the goof you're compensating for will be fixed the next time you patch or upgrade the OS.

And if security is a concern, you can still avoid this by either implementing effective external security mechanisms (extended facls, role access databases, etc) or figuring out a way to achieve your desired end that doesn't pose a security risk. I don't know if Perl (to this day) actually "recommends" that you ever write any "suid" code (generally speaking, creating a script or binary that will be run as a different user - Set User ID - usually one with elevated system privileges) in Perl script unless you're protecting it by taking additional measures. Generally, if I "have" to write an "suid" program, I'll write it in "C" (like the one in our post on securing suid programs with a simple C wrapper, which doesn't even come close to the protection provided by the one-and-only Wietse Zweitze Venema's mother of all SUID C Wrappers.

Bottom line: It's up to you if you want to implement this sort of functionality. To my way of thinking, short of ensuring you don't get screwed on a work-for-hire at an institution in which you have no trust, there's really no reason to encrypt (I mean convert into binary ;) your Perl script. It's a pretty cool idea, but...

Cheers,

, Mike




Discover the Free Ebook that shows you how to make 100% commissions on ClickBank!



Please note that this blog accepts comments via email only. See our Mission And Policy Statement for further details.