Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Loadable Bash Builtin

I'm writing a strcmp bash builtin. It compiles fine, but when I try to enable it, I get:

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

The big parts of my builtin:

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 */
};

The compile line (from the expanded make file):

~/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

I have googled ET_DYN and ET_EXEC, and only found links to questions like this.

like image 640
David Souther Avatar asked Aug 31 '11 04:08

David Souther


2 Answers

Did you notice the -c flag? That's keeping it from linking. Replace that with -shared, as @shr mentioned

like image 112
stanparker Avatar answered Sep 24 '22 19:09

stanparker


A little follow up on an answer to my specific question (ET_DYN and ET_EXEC), as well as an expansion on WHY @stanparker's answer is correct.

ET_DYN and ET_EXEC are ELF Executable types. In the ELF header, there is a field Elf32_Half e_type or Elf64_Half e_type with several possibly ET_* enums. I'm guessing ET is "Executable Type", EXEC executable and DYN Dynamic. This should all be enough to show that the emitted artifact was not, in fact, an executable object of any kind, and should have encouraged looking closer at the GCC flags. (For more on the ELF headers, http://www.sco.com/developers/gabi/1998-04-29/ch4.eheader.html)

Now that we see we aren't linking, let's remove the -c flag. Then, we'll get a second error (this time somewhere in the compile),

$ 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

There are actually two errors here. The first is "undefined reference to `main'", the second is "undefined reference to `make_builtin_argv'" (a bash internal function). The last line is enough to show us GCC is dying during linking. The function _start is a common entry point defined by glibc, which itself actually calls main in the program. At this point, duh, we aren't making an executable, but a shared lib. Adding -shared to the command line gets us compiling perfectly.

So, why wasn't make giving me the "Correct" command line? Makefile.in doesn't dynamically test for source files, so I should have added the .c and .o targets by hand, then rerunning ./configure. After doing so, we get

$ make strcmp 
gcc [...] -c -o strcmp.o strcmp.c
gcc -shared -Wl,-soname,strcmp  -L./lib/termcap  -o strcmp strcmp.o 

Does it work?

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

That's what I expect it to do, so it seems it does work.

Anyway, the point of me writing this up is that this is not the first time I've personally gotten messed up on GCC and C compiling in general. This is not the first time I've seen someone have these problems in general. There is a tremendous amount of work that goes into getting a successful C compile, and each phase is important. So, I'm writing this up to remind myself of exactly what GCC (cc, ld, and the elf libs) were doing, why the one little character here and there is important, and the overall discovery process. I haven't seen it typed up anywhere else, so here is what I have.

PS. For those interested in this builtin, it will be on my site, http://davidsouther.com/2011/08/bash-strcmp-builtin/

like image 38
David Souther Avatar answered Sep 22 '22 19:09

David Souther