7

我正在编写一个内置的 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,只找到了此类问题的链接。

4

3 回答 3

10

你注意到-c国旗了吗?这使它无法链接。-shared如@shr所述,将其替换为

于 2011-08-31T04:48:29.017 回答
7

对我的具体问题(ET_DYN 和 ET_EXEC)的答案进行一点跟进,以及扩展为什么 @stanparker 的答案是正确的。

ET_DYN 和 ET_EXEC 是 ELF 可执行文件类型。在 ELF 头中,有一个字段Elf32_Half e_typeElf64_Half e_type几个可能的 ET_* 枚举。我猜 ET 是“可执行类型”、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

这里实际上有两个错误。第一个是“对 `main' 的未定义引用”,第二个是“对 `make_builtin_argv' 的未定义引用”(一个 bash 内部函数)。最后一行足以向我们展示 GCC 在链接期间正在死亡。函数_start是glibc定义的一个通用入口点,它本身实际上在程序中调用了main。在这一点上,呃,我们不是在制作一个可执行文件,而是一个共享库。添加-shared到命令行可以让我们完美地编译。

那么,为什么不给我“正确”的命令行呢?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/

于 2011-08-31T14:46:52.503 回答
2

我不确定,但是...曾经尝试过gcc -shared吗?

于 2011-08-31T04:38:30.677 回答