这里的 AUTOLOAD
可以理解为自动加载。具体来说就是,在正常情况下,我们不能调用一个尚未定义的函数(子例程)。不过,如果在未定义函数的包中有一个名为 AUTOLOAD
的函数,那么对未定义函数的调用都会路由至这个 AUTOLOAD
函数,并且会为该函数提供相同的参数。因此,我们可以在 AUTOLOAD
函数里面针对未定义的函数进行特殊处理,比如实现未定义的函数,然后调用该函数,就好像这个函数一直都存在一样。
比如,下面的示例程序会在你调用未定义函数时发出警告,而不是直接退出:
#!/usr/bin/env perlsub AUTOLOAD {our $AUTOLOAD;warn "You attempt to call an undefined function: $AUTOLOAD\n";
}&foo; # $AUTOLOAD will be set to main::foo
print "Exit normally ...\n"
运行结果如下所示:
$ ./autoload.pl
You attempt to call an undefined function: main::foo
Exit normally ...
下面是一个更加实用的例子,即我们在 AUTOLOAD
中实现未定义的函数:
#!/usr/bin/env perlsub AUTOLOAD {my $name = our $AUTOLOAD;*$AUTOLOAD = sub { print "calling function $name(@_)\n"; };goto &$AUTOLOAD;
}foo(30);
goo(40);
hoo(50);
运行结果如下所示:
$ ./autoload_2.pl
calling function main::foo(30)
calling function main::goo(40)
calling function main::hoo(50)
在OpenSSL
项目中的很多地方都有用到 perl
语言,它主要负责项目建构和汇编代码的生成工作。其中,在生成加解密算法汇编优化代码的 perl
脚本中,有很多架构都用到了 AUTOLOAD
机制去简化汇编指令的书写。下面看一个 OpenSSL
中 x86
实现的例子,从 crypto/chacha/asm/chacha-x86_64.pl
文件中节选出如下代码:
#!/usr/bin/env perlsub AUTOLOAD() # thunk [simplified] 32-bit style perlasm
{ my $opcode = $AUTOLOAD; $opcode =~ s/.*:://;my $arg = pop;$arg = "\$$arg" if ($arg*1 eq $arg);$code .= "\t$opcode\t".join(',',$arg,reverse @_)."\n";
}@x=("%eax","%ebx","%ecx","%edx",map("%r${_}d",(8..11)),"%nox","%nox","%nox","%nox",map("%r${_}d",(12..15)));
@t=("%esi","%edi");sub ROUND { # critical path is 24 cycles per round
my ($a0,$b0,$c0,$d0)=@_;
my ($a1,$b1,$c1,$d1)=map(($_&~3)+(($_+1)&3),($a0,$b0,$c0,$d0));
my ($xc,$xc_)=map("\"$_\"",@t);
my @x=map("\"$_\"",@x);("&add (@x[$a0],@x[$b0])", # Q1"&xor (@x[$d0],@x[$a0])","&rol (@x[$d0],16)","&add (@x[$a1],@x[$b1])", # Q2"&xor (@x[$d1],@x[$a1])","&rol (@x[$d1],16)","&add ($xc,@x[$d0])","&xor (@x[$b0],$xc)","&rol (@x[$b0],12)","&add ($xc_,@x[$d1])","&xor (@x[$b1],$xc_)","&rol (@x[$b1],12)",)
}foreach (&ROUND(0, 4, 8,12)) { eval; }
foreach (&ROUND(0, 5,10,15)) { eval; }print "$code\n";
表面上看,add()
,xor()
,rol()
这些函数并没有声明和实现,但在 AUTOLOAD
函数中进行了统一的处理,比如,将 &add(xx, yy)
函数调用转换为了 add yy,xx
指令字符串。
运行结果如下所示:
$ ./autoload_3.pl add %r8d,%eaxxor %eax,%r12drol $16,%r12dadd %r9d,%ebxxor %ebx,%r13drol $16,%r13dadd %r12d,%esixor %esi,%r8drol $12,%r8dadd %r13d,%edixor %edi,%r9drol $12,%r9dadd %r9d,%eaxxor %eax,%r15drol $16,%r15dadd %r10d,%ebxxor %ebx,%r12drol $16,%r12dadd %r15d,%esixor %esi,%r9drol $12,%r9dadd %r12d,%edixor %edi,%r10drol $12,%r10d