使用UCLIBC交叉编译PHP

9

这是一个重新发布的内容,之前的帖子已被关闭,转移到Serverfault并再次关闭。我认为这篇文章是一个有效的stackoverflow问题,因为我认为它是由某些自动化/编译/链接错误引起的。这是一个编程问题,而不是服务器管理员问题。

交叉编译 PHP

https://serverfault.com/questions/418521/cross-compile-php

开始发布

我已经下载了 PHP 5.4.0 源代码,解压缩并移动到源文件夹中。

我使用以下命令进行配置:

./configure --build=x86_64-unknown-linux-gnu --host=arm-linux-uclibcgnueabi --prefix=/usr/arm/www CC="arm-linux-uclibcgnueabi-gcc --sysroot=/toolchains/gnu_cortex-a9_tools/"  --disable-libxml --disable-dom  --without-iconv --without-openssl --disable-simplexml --disable-xml --disable-xmlreader --disable-xmlwriter --without-pear --without-sqlite3 --disable-pdo --without-pdo-sqlite --disable-phar  --with-config-file-path=/etc/

接下来是

make

没有错误,一切正常运行。接下来我执行 make install 命令。

make install

一切都运行良好。 我将其移动到目标平台并运行。

/usr/arm/www/bin/php -v
PHP 5.4.0 (cli) (built: Aug 15 2012 16:07:41) 
Copyright (c) 1997-2012 The PHP Group
Zend Engine v2.4.0, Copyright (c) 1998-2012 Zend Technologies

我使用我的Web服务器和直接使用PHP测试了一个简单的主页。

<?php echo "hello" ?>
# php index.php
hello

它按预期工作。 接下来我进行测试:

<?php
$output = shell_exec('ls -lart');
echo "<pre>$output</pre>";
?>

oh noes~

# php shell.php 

Segmentation fault

我测试另一个脚本:

#!/bin/php
<?php

echo "hello";
$handle = fopen("info.txt", "r");
echo $handle;
?>

同样的结果:

# php index.php 
helloSegmentation fault

我是否有一个php.ini文件?

# /usr/arm/www/bin/php --ini
Configuration File (php.ini) Path: /etc/
Loaded Configuration File:         /etc/php.ini

是的,但没有禁用的功能。 测试strace /usr/arm/www/bin/php index.php

lstat("/srv/www/info.txt", {st_mode=S_IFREG|0644, st_size=20, ...}) = 0
open("/srv/www/info.txt", O_RDONLY)     = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=20, ...}) = 0
lseek(3, 10, SEEK_CUR)                  = 0
--- SIGSEGV (Segmentation fault) @ 0 (0) ---
+++ killed by SIGSEGV +++

文件 info.txt 存在并且拥有读/写权限。

测试 strace /usr/arm/www/bin/php shell.php

fcntl64(3, F_GETFL)                     = 0 (flags O_RDONLY)
ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, 0x7e31fddc) = -1 EINVAL (Invalid argument)
vfork()                                 = 3324
close(4)                                = 0
fstat(3, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
read(3, "total 24\n-rw-rw-r--    1 1001    "..., 8192) = 468
read(3, ""..., 8192)                    = 0
--- SIGCHLD (Child exited) @ 0 (0) ---
close(3)                                = 0
wait4(3324, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 3324
--- SIGSEGV (Segmentation fault) @ 0 (0) ---
+++ killed by SIGSEGV +++

如果我通过gdb运行index.php,它会给我以下结果:

Starting program: /usr/arm/www/bin/php index.php
hello
Program received signal SIGSEGV, Segmentation fault.
zend_do_fcall_common_helper_SPEC (execute_data=0x2ac7a040) at /home/maiden/Downloads/php-5.4.0/Zend/zend.h:391
391 /home/maiden/Downloads/php-5.4.0/Zend/zend.h: No such file or directory.
    in /home/maiden/Downloads/php-5.4.0/Zend/zend.h

我从shell.php运行gdb得到以下信息:

启动程序:/usr/arm/www/bin/php shell.php

Program received signal SIGSEGV, Segmentation fault.

zend_do_fcall_common_helper_SPEC (execute_data=0x2ab76040) at /home/maiden/Downloads/php-5.4.0/Zend/zend.h:391
391 in /home/maiden/Downloads/php-5.4.0/Zend/zend.h

zend.h位于/usr/arm/www/include/php/Zend/,显然在交叉编译过程中出现了问题。我错过了什么?我没有找到任何配置标志来纠正这个问题,将符号链接创建到预期位置可以去掉gdb输出,但是php仍然会导致段错误。

感谢您的帮助!

更新:

# valgrind php test.php
==2181== Memcheck, a memory error detector
==2181== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==2181== Using Valgrind-3.8.0 and LibVEX; rerun with -h for copyright info
==2181== Command: php test.php
==2181==
==2181== Conditional jump or move depends on uninitialised value(s)
==2181==    at 0x4004EC8: ??? (in /lib/ld-uClibc-0.9.30-nptl.so)
==2181==
==2181== Invalid read of size 4
==2181==    at 0x4004D48: _dl_get_ready_to_run (in /lib/ld-uClibc-0.9.30-nptl.so)
==2181==  Address 0x7d4cc304 is just below the stack ptr.  To suppress, use: --workaround-gcc296-bugs=yes
==2181==
==2181== Invalid read of size 4
==2181==    at 0x48C348C: __uClibc_main (in /lib/libuClibc-0.9.30-nptl.so)
==2181==  Address 0x7d4cc554 is just below the stack ptr.  To suppress, use: --workaround-gcc296-bugs=yes
==2181==
==2181== Invalid write of size 4
==2181==    at 0x233010: __eqdf2 (ieee754-df.S:1120)
==2181==  Address 0x7d4cb0bc is just below the stack ptr.  To suppress, use: --workaround-gcc296-bugs=yes
==2181==
Warning: shell_exec(): Unable to execute 'ls -lart' in /test.php on line 3
==2181== Invalid read of size 4
==2181==    at 0x1FF1AC: zend_do_fcall_common_helper_SPEC (zend.h:391)
==2181==    by 0x1F3D17: execute (zend_vm_execute.h:410)
==2181==    by 0x18B217: zend_execute_scripts (zend.c:1279)
==2181==    by 0x1365BB: php_execute_script (main.c:2473)
==2181==    by 0x22B52B: do_cli (php_cli.c:988)
==2181==    by 0x22BD4B: main (php_cli.c:1364)
==2181==  Address 0x8 is not stack'd, malloc'd or (recently) free'd
==2181==
Segmentation fault

更新2

重新运行带有memcheck的valgrind,输出结果与之前差不多,但是有一些新发现:

php: can't resolve symbol '__libc_freeres'

更新3

虽然Valgrind没有成功,但我继续使用GDB,在目标系统上创建了文件夹/home/maiden/..etc,并复制了我的php/include文件夹中的内容并重新运行GDB。现在我得到了这个错误信息:

(gdb) run index.php 
Starting program: /bin/php index.php
hello
Program received signal SIGSEGV, Segmentation fault.
zend_do_fcall_common_helper_SPEC (execute_data=0x2ab34040) at /home/maiden/Downloads/php-5.4.5/Zend/zend.h:391
warning: Source file is more recent than executable.
391     return --pz->refcount__gc;

这与昨天六八零在评论中写的非常相似。我已经尝试过PHP版本5.3.5、5.4.0和5.4.5,在所有版本中都出现了同样的错误。

更新4

我下载了一个新的glibc工具链,用glibc交叉编译了一个新的busybox,创建了一个chroot jail,在我的uclibc box上测试了使用glibc而不是uclibc交叉编译的php,并且它可以运行!但我仍然需要让php在我的uclibc环境中工作....


一些想法。切换到http://www.eglibc.org/faq。还有一些uclibc的设置,使其与glibc稍微兼容,例如在使用malloc(0)调用时分配内存。 - Prof. Falken
你能用像readelf这样的工具检查二进制文件,看它们的版本、字节序等是否相同吗?你尝试过使用更新版本的uClibc吗?我还会尝试使用--enable-shared --disable-static(切换启用/禁用)以及--with-gnu-ld进行实验。 - auselen
1
你能在任何ARM模拟器上重现吗?例如armware、qemu、ARMphethamine。如果可以,并且您可以给我们详细的说明,包括如何逐步复制主机和目标环境以及您正在执行的确切操作步骤,请不要遗漏任何细节,下载链接或确切版本号必须提供。不幸的是,这不是一个解决问题的合适渠道,因为有太多变量,最多只能进行猜测。很抱歉您已经与此问题斗争了这么长时间,我知道这一定很令人沮丧,也许如果我们能按照您的说明重现问题,我们可能真的会有所进展。 - nickl-
1
我不知道这是否有所帮助,但如果您想看另一个嵌入式项目如何使用uClibc编译PHP,请查看http://freetz.org/browser/trunk/make/php。它在MIPS上运行,但某些配置和工具链问题可能相似。在存储库中,您还可以找到用于uClibc的工具链makefile和补丁。 - kriegaex
1
只是一个提示:列出文件名的 gdb 错误和 valgrind 错误并不是在那些位置寻找文件;这些位置是编译时原始主机上的位置。php 运行时不需要包含文件... - Stobor
显示剩余7条评论
1个回答

3
我会检查 uClibc 的 configure.log,以查看是否启用了 ARCH_USE_MMU 和 fork。如果没有启用 vfork 将被替换为 fork,shell_exec 可能会使用它。vfork 的主要问题是,父进程和子进程使用相同的内存空间,这会导致奇怪的崩溃。

我也想检查一下。但是我只从我的CPU制造商那里得到了二进制块。但如果它被禁用了,我会感到惊讶的。我们使用相同的工具链运行了一个webkit浏览器、Qt和DirectFB。 - Maidenone

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接