Stas Bekman wrote:

[...]

so that means that the linker decides that those symbols aren't used (and they indeed aren't) and it drops them. I think I've seen that behavior before. Just to prove that idea, try to use them somewhere (e.g some dummy function in mod_perl.c).

Exactly, when the target of a link operation is an actual binary, the linker will remove all unused functions. That is not the
case with a .so where the linker has no possible way of knowing what might be needed at a later time.

So, attached is a patch similar to httpd's ap_hack_* to work around this problem.

In a nutshell, create a modperl_exports.c that contains this :

const void *modperl_ugly_hack = NULL;
const void *modperl_hack_$name = (const void *)modperl_$name;
[...]

where $name is each and every single public modperl API function.

This doesn't even guarantee that the linker won't delete these entries from there, since it
will detect correctly that not a single external compilation uint needed any of the symbols
in modperl_exports.c. Thus, to create that dependency, in mod_perl.c :
const void *modperl_suck_in_ugly_hack(void);
const void *modperl_suck_in_ugly_hack(void)
{
extern const void *modperl_ugly_hack;
return modperl_ugly_hack;
}

And that does create an external link/dependency and the linker keeps all symbols around.

As a nice side effect, this might be of some help to people on more esoteric platforms.




Index: lib/ModPerl/Code.pm
===================================================================
RCS file: /home/cvs/modperl-2.0/lib/ModPerl/Code.pm,v
retrieving revision 1.125
diff -u -I$Id -r1.125 Code.pm
--- lib/ModPerl/Code.pm	2 Jul 2004 19:04:32 -0000	1.125
+++ lib/ModPerl/Code.pm	21 Sep 2004 06:17:50 -0000
@@ -637,6 +637,7 @@
    generate_largefiles         => {h => 'modperl_largefiles.h'},
    generate_constants          => {h => 'modperl_constants.h',
                                    c => 'modperl_constants.c'},
+   generate_exports            => {c => 'modperl_exports.c'},
 );
 
 my @c_src_names = qw(interp tipool log config cmd options callback handler
@@ -645,7 +646,7 @@
                      const constants apache_compat error debug
                      common_util common_log);
 my @h_src_names = qw(perl_unembed);
-my @g_c_names = map { "modperl_$_" } qw(hooks directives flags xsinit);
+my @g_c_names = map { "modperl_$_" } qw(hooks directives flags xsinit exports);
 my @c_names   = ('mod_perl', (map "modperl_$_", @c_src_names));
 sub c_files { [map { "$_.c" } @c_names, @g_c_names] }
 sub o_files { [map { "$_.o" } @c_names, @g_c_names] }
@@ -1083,6 +1084,12 @@
                 unless $seen_const{$class}{$name}
         }
     }
+}
+
+sub generate_exports {
+    my($self, $c_fh) = @_;
+    require ModPerl::WrapXS;
+    ModPerl::WrapXS->generate_exports($c_fh);
 }
 
 # src/modules/perl/*.c files needed to build APR/APR::* outside
Index: lib/ModPerl/WrapXS.pm
===================================================================
RCS file: /home/cvs/modperl-2.0/lib/ModPerl/WrapXS.pm,v
retrieving revision 1.79
diff -u -I$Id -r1.79 WrapXS.pm
--- lib/ModPerl/WrapXS.pm	21 Sep 2004 05:54:56 -0000	1.79
+++ lib/ModPerl/WrapXS.pm	21 Sep 2004 06:17:51 -0000
@@ -1267,5 +1267,35 @@
     return \%stats;
 }
 
+sub generate_exports {
+    my($self, $fh) = @_;
+
+    if (!$build->should_build_apache) {
+        print $fh <<"EOF";
+/* This is intentionnaly left blank, only usefull for static build */
+const void *modperl_ugly_hack = NULL;
+EOF
+        return;
+    }
+    
+    print $fh <<"EOF";
+/* 
+ * This is indeed a ugly hack!
+ * See also src/modules/perl/mod_perl.c for modperl_ugly_hack
+ * If we don't build such a list of exported API functions, the over-zealous
+ * linker can and will remove the unused functions completely. In order to
+ * avoid this, we create this object and modperl_ugly_hack to create a 
+ * dependency between all the exported API and mod_perl.c
+ */
+const void *modperl_ugly_hack = NULL;
+EOF
+
+    for my $entry (@$ModPerl::FunctionTable) {
+        next if $self->func_is_static($entry);
+        ( my $name ) = $entry->{name} =~ /^modperl_(.*)/;
+        print $fh "const void *modperl_hack_$name = (const void *)modperl_$name;\n";
+    }
+}
+
 1;
 __END__
Index: src/modules/perl/.cvsignore
===================================================================
RCS file: /home/cvs/modperl-2.0/src/modules/perl/.cvsignore,v
retrieving revision 1.12
diff -u -I$Id -r1.12 .cvsignore
--- src/modules/perl/.cvsignore	11 Sep 2004 00:07:33 -0000	1.12
+++ src/modules/perl/.cvsignore	21 Sep 2004 06:17:51 -0000
@@ -1,3 +1,4 @@
+modperl_exports.c
 modperl_hooks.h
 modperl_hooks.c
 modperl_flags.h
Index: src/modules/perl/mod_perl.c
===================================================================
RCS file: /home/cvs/modperl-2.0/src/modules/perl/mod_perl.c,v
retrieving revision 1.221
diff -u -I$Id -r1.221 mod_perl.c
--- src/modules/perl/mod_perl.c	18 Sep 2004 04:33:34 -0000	1.221
+++ src/modules/perl/mod_perl.c	21 Sep 2004 06:17:51 -0000
@@ -1034,6 +1034,17 @@
     return retval;
 }
 
+/* This ugly hack pulls in any function listed in
+ * modperl_exports.c. Otherwise, the over-zealous
+ * linker would remove unused api functions
+ */
+const void *modperl_suck_in_ugly_hack(void);
+const void *modperl_suck_in_ugly_hack(void)
+{
+    extern const void *modperl_ugly_hack;
+    return modperl_ugly_hack;
+}
+
 module AP_MODULE_DECLARE_DATA perl_module = {
     STANDARD20_MODULE_STUFF, 
     modperl_config_dir_create, /* dir config creater */

Attachment: signature.asc
Description: OpenPGP digital signature



Reply via email to