可装载的Bash内置

Dav*_*her 7 c bash built-in strcmp

我正在写一个strcmp bash内置.编译很好,但是当我尝试启用它时,我得到:

$ enable -f ./strcmp strcmp
bash: enable: cannot open shared object ./strcmp: ./strcmp: only ET_DYN and ET_EXEC can be loaded
Run Code Online (Sandbox Code Playgroud)

我内置的重要部分:

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 */
};
Run Code Online (Sandbox Code Playgroud)

编译行(来自扩展的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
Run Code Online (Sandbox Code Playgroud)

我用Google搜索ET_DYN和ET_EXEC,只找到了这样的问题的链接.

sta*_*ker 10

你注意到-c国旗了吗?这使它无法链接.用-shared@shr提到的替换为


Dav*_*her 7

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

ET_DYN和ET_EXEC是ELF可执行类型.在ELF头中,有一个字段Elf32_Half e_type或Elf64_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
Run Code Online (Sandbox Code Playgroud)

这里实际上有两个错误.第一个是"对'main'的未定义引用",第二个是"对`make_builtin_argv'的未定义引用"(bash内部函数).最后一行足以告诉我们GCC在链接期间正在死亡.函数_start是由glibc定义的公共入口点,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 
Run Code Online (Sandbox Code Playgroud)

它有用吗?

$ enable -f ./strcmp strcmp
$ strcmp "hi" "ho"
$ echo $?
2
$ strcmp "hi" "ha"
$ echo $?
1
$ strcmp "hi" "hi"
$ echo $?
0
Run Code Online (Sandbox Code Playgroud)

这就是我期望它做的,所以看起来确实有效.

无论如何,我写这篇文章的重点是,这不是我个人第一次搞砸GCC和C编译.这不是我第一次看到有人遇到这些问题.获得成功的C编译需要做大量的工作,每个阶段都很重要.所以,我写这篇文章是为了提醒自己GCC(cc,ld和elf libs)究竟在做什么,为什么这里和那里的一个小角色很重要,以及整个发现过程.我还没有看到它在其他任何地方打字,所以这就是我所拥有的.

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