可加载的Bash内置命令

8

我正在编写一个strcmp bash内置函数。它可以编译通过,但是当我尝试启用它时,会出现以下错误:

$ enable -f ./strcmp strcmp
bash: enable: cannot open shared object ./strcmp: ./strcmp: only ET_DYN and ET_EXEC can be loaded

我的内置部分的主要组成部分:
strcmp_builtin (list)
WORD_LIST *list;

char *strcmp_doc[] = {
    (char *)NULL
};

struct builtin strcmp_struct = {
    "strcmp", /* builtin name */
    strcmp_builtin, /* function implementing the builtin */
    BUILTIN_ENABLED, /* initial flags for builtin */
    strcmp_doc, /* array of long documentation strings. */
    "strcmp 'string 1' 'string 2'", /* usage synopsis; becomes short_doc */
    0 /* reserved for internal use */
};

编译行(从扩展的make文件中):
~/bash-4.2/examples/loadables $ gcc -fPIC -DHAVE_CONFIG_H -DSHELL \
-g -O2 -I. -I.. -I../.. -I../../lib -I../../builtins -I../../include \
-I~/bash-4.2 -I~/bash-4.2/lib -I~/bash-4.2/builtins  -c \
-o strcmp strcmp.c

我已经搜索过ET_DYN和ET_EXEC,但只找到了像这样的问题链接。

3个回答

10

你有没有注意到-c标志?那是防止链接的。像@shr提到的那样,将其替换为-shared


1
我真傻,竟然相信 make 文件而没有仔细查看。是的,它并不喜欢。谢谢! - David Souther

8

关于我的具体问题(ET_DYN 和 ET_EXEC),以及为什么 @stanparker 的答案是正确的,我想再做一些说明。

ET_DYN 和 ET_EXEC 是 ELF 可执行文件类型。在 ELF 头中,有一个字段叫做 Elf32_Half e_typeElf64_Half e_type,其中包含多个可能的 ET_* 枚举值。我猜 ET 是 "Executable Type" 的缩写,EXEC 代表可执行文件,DYN 代表动态链接库。这应该足以说明所生成的二进制文件实际上不是任何类型的可执行对象,并且应该让我们更加仔细地查看 GCC 标志。(更多关于 ELF 头的信息,请参考 http://www.sco.com/developers/gabi/1998-04-29/ch4.eheader.html

既然我们发现没有进行链接,那么就去掉 -c 标志。然后,我们会得到第二个错误(这次是在编译过程中某处出错),

$ gcc [...] -o strcmp.o strcmp.c
/usr/lib/gcc/i686-redhat-linux/4.6.0/../../../crt1.o: In function `_start':
(.text+0x18): undefined reference to `main'
/tmp/ccaiMtdc.o: In function `strcmp_builtin':
~/bash-4.2/examples/loadables/strcmp.c:32: undefined reference to `make_builtin_argv'
collect2: ld returned 1 exit status

实际上这里有两个错误。第一个是“undefined reference to `main'”,第二个是“undefined reference to `make_builtin_argv'”(这是bash内部函数)。最后一行足以表明GCC在链接过程中崩溃了。函数_start是由glibc定义的常见入口点,实际上它调用程序中的main。此时,我们并没有生成可执行文件,而是生成了共享库。将-shared添加到命令行就可以完美编译了。
那么,为什么make没有给我“正确”的命令行呢?Makefile.in没有动态测试源代码文件,所以我应该手动添加.c和.o目标,然后重新运行./configure。这样做之后,我们就会得到:
$ make strcmp 
gcc [...] -c -o strcmp.o strcmp.c
gcc -shared -Wl,-soname,strcmp  -L./lib/termcap  -o strcmp strcmp.o 

它能正常工作吗?

$ enable -f ./strcmp strcmp
$ strcmp "hi" "ho"
$ echo $?
2
$ strcmp "hi" "ha"
$ echo $?
1
$ strcmp "hi" "hi"
$ echo $?
0

我希望它能够做到这一点,所以看起来它确实有效。

无论如何,我写这篇文章的目的是因为这不是我第一次在GCC和C编译方面遇到问题。这也不是我第一次看到别人普遍存在这些问题。编写成功的C编译需要大量的工作,每个阶段都很重要。因此,我写下这篇文章,提醒自己GCC(cc、ld和elf库)正在做什么,为什么这里和那里的一个小字符很重要,以及总体发现过程。我没有在任何其他地方看到过它被打印出来,所以这就是我所拥有的。

PS. 对于那些对这个内置程序感兴趣的人,它将会在我的网站上 http://davidsouther.com/2011/08/bash-strcmp-builtin/ 上。


2
我不确定,但是... 你试过 gcc -shared 吗?

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