git workflow

I've been hacking a lot of kernel headers lately, which gives you plenty of time to think as the rebuild magic happens. So I thought I'd try to come up to speed a bit more on git, the new kernel SCM.

Which lead me to attempt a diagram explaining how things fit together. As usual with these things, I'm not sure if it makes things clearer or more confusing.

git workflow diagram

xfig source available if you want to make it better.

What exactly does -Bsymblic do?

-Bsymbolic is described by the ld man page as

When creating a shared library, bind references to global symbols to the definition within the shared library, if any. Normally, it is possible for a program linked against a shared library to override the definition within the shared library.  This option is only meaningful on ELF platforms which support shared libraries.

Indeed, it is interesting to peer under the hood a little. In fact, the only thing the -Bsymbolic flag does when building a shared library is add a flag in the dynamic section of the binary called DT_SYMBOLIC. Having a look at the ABI description of the flag is a little more instructive.

`` This element's presence in a shared object library alters the dynamic linker's symbol resolution algorithm for references within the library. Instead of starting a symbol search with the executable file, the dynamic linker starts from the shared object itself. If the shared object fails to supply the referenced symbol, the dynamic linker then searches the executable file and other shared objects as usual.``

Ahh, now we can have a peek into the dynamic loader to see what exactly it does with this flag. Pull open the glibc source and have a look at `elf/dl-load.c <http://sources.redhat.com/cgi-bin/cvsweb.cgi/libc/elf/dl-load.c?rev=1.249.2.17&content-type=text/x-cvsweb-markup&cvsroot=glibc>`_, particularly at the bit in _dl_map_obj_from_fd where we have

/* If this object has DT_SYMBOLIC set modify now its scope.  We don't
    have to do this for the main map.  */
 if ((mode & RTLD_DEEPBIND) == 0
     && __builtin_expect (l->l_info[DT_SYMBOLIC] != NULL, 0)
     && &l->l_searchlist != l->l_scope[0])
   {
     /* Create an appropriate searchlist.  It contains only this map.
        This is the definition of DT_SYMBOLIC in SysVr4.  */
     l->l_symbolic_searchlist.r_list =
       (struct link_map **) malloc (sizeof (struct link_map *));

     if (l->l_symbolic_searchlist.r_list == NULL)
       {
         errstring = N_("cannot create searchlist");
         goto call_lose_errno;
       }

     l->l_symbolic_searchlist.r_list[0] = l;
     l->l_symbolic_searchlist.r_nlist = 1;

     /* Now move the existing entries one back.  */
     memmove (&l->l_scope[1], &l->l_scope[0],
              (l->l_scope_max - 1) * sizeof (l->l_scope[0]));

     /* Now add the new entry.  */
     l->l_scope[0] = &l->l_symbolic_searchlist;
   }

So we can see (in typical glibcistic code) that we insert ourselves at the beginning of the link map, and move everything else along further down the chain.

Finally, an example to illustrate. It's a bit long, but worth understanding.

ianw@lime:/tmp/symbolic$ cat Makefile
all: test testsym

clean:
        rm -f *.so test testsym

liboverride.so : override.c
        $(CC) -shared -fPIC -o liboverride.so override.c

libtest.so : libtest.c
        $(CC) -shared -fPIC -o libtest.so libtest.c

libtestsym.so : libtest.c
        $(CC) -shared -fPIC -Wl,-Bsymbolic -o libtestsym.so libtest.c

test : test.c libtest.so liboverride.so
        $(CC) -L. -ltest -o test test.c

testsym : test.c libtestsym.so liboverride.so
        $(CC) -L. -ltestsym -o testsym test.c

ianw@lime:/tmp/symbolic$ cat libtest.c
#include <stdio.h>

int foo(void) {
        printf("libtest foo called\n");
        return 1;
}

int test_foo(void)
{
        return foo();
}
ianw@lime:/tmp/symbolic$ cat override.c
#include <stdio.h>

int foo(void)
{
        printf("override foo called\n");
        return 0;
}
ianw@lime:/tmp/symbolic$ cat test.c
#include <stdio.h>

int main(void)
{
        printf("%d\n", test_foo());
}


ianw@lime:/tmp/symbolic$ make
cc -shared -fPIC -o libtest.so libtest.c
cc -shared -fPIC -o liboverride.so override.c
cc -L. -ltest -o test test.c
cc -shared -fPIC -Wl,-Bsymbolic -o libtestsym.so libtest.c
cc -L. -ltestsym -o testsym test.c

So we have an application, a library (compiled once with -Bsymbolic and once without) and another library with a symbol foo that will override our original definition.

ianw@lime:/tmp/symbolic$ LD_LIBRARY_PATH=. ./test
libtest foo called
1
ianw@lime:/tmp/symbolic$ LD_LIBRARY_PATH=. ./testsym
libtest foo called
1

No surprises here ... both libraries call the "builtin" foo and everything is fine.

ianw@lime:/tmp/symbolic$ LD_LIBRARY_PATH=. LD_PRELOAD=./liboverride.so  ./test
override foo called
0
ianw@lime:/tmp/symbolic$ LD_LIBRARY_PATH=. LD_PRELOAD=./liboverride.so  ./testsym
libtest foo called
1

Now we see the difference. The preloaded foo was ignored in the second case, because the libtest was told to look within itself for symbols before looking outside.

-Bsymbolic is a rather big hammer to maintain symbol visiblity with however; it makes it all or nothing. Chances are you'd be better of with a version script. For example, with the following version script we can achieve the same thing.

ianw@lime:/tmp/symbolic$ cat Versions
{global: test_foo;  local: *; };
ianw@lime:/tmp/symbolic$ make
cc -shared -fPIC -Wl,-version-script=Versions -o libtestver.so libtest.c
cc -L. -ltestver -o testver test.c
ianw@lime:/tmp/symbolic$ LD_LIBRARY_PATH=. LD_PRELOAD=./liboverride.so ./testver
libtest foo called
1

You can see that since the version of foo in libtestver.so was local it got bound before the LD_PRELOAD, so has the same effect as -Bsymbolic.

Moral of the story? Version your symbols!

Update 2010-03-22 : see the update for more information on code optimisation with -Bsymbolic.

Stripping unused functions

benno raised an interesting question on getting rid of unused functions from a binary. If you link a group of object files together, the linker will be smart enough to leave out any files that it know doesn't get used. But what about functions that don't get used?

The best solution I could think of was to use -ffunction-sections and then --gc-sections to remove those sections that aren't used.

$ cat foo.c
int foo(void) {};
int bar(void) {};

$ cat main.c
int
main(void)
{
  foo();
  return 0;
};

$ gcc -c main.c
$ gcc -c -ffunction-sections foo.c
$ gcc -Wl,--gc-sections foo.o main.o -o program
$ objdump -d ./program | grep bar

This seems well out of scope for the linker to resolve, as it's job isn't to splice and dice text sections. The compiler doesn't really have enough information to see what is going on either. I think it would be possible to analyse the relocations in a group of pre-linked object files, and then compare that against a list of global functions in those same object files and if there isn't a relocation against it, prune the function out of the object.

I think the nicest way to do that would be with libelf wrappers for Python. But surely someone has looked at doing that before?

A 10 second guide to creating a DocBook document

  • The Definitive Guide is a good start, but probably won't help you actually make a document.

  • You have two choices, XML or SGML (see the guide). I've always used SGML, but make it like XML (see below). This is because doing things like inserting a text file or program listing from a foreign file with XML requires all sorts of playing with tools that seem mostly to be based on Java, which sucks on any platform !x86, which I use a lot. It seems much easier to just use jade to get everything done.

  • Use the XML declaration for SGML so you can have closed tags (e.g. <tag />). I think this turns it into something defined as WebSGML. Close all your tags (such as <imagedata>) and make sure all your tags are lower case. This means if you want to make it XML later, you can. I've also found xsltproc does a better job at finding problems than jade.

  • You'll want a CSS file to style your HTML output. Create a DSSSL script that looks like below.

    <!DOCTYPE style-sheet PUBLIC "-//James Clark//DTD DSSSL Style Sheet//EN" [
    <!ENTITY docbook.dsl PUBLIC "-//Norman Walsh//DOCUMENT DocBook HTML Stylesheet//EN" CDATA dsssl>
    ]>
    <style-sheet>
    
    <style-specification id="html" use="docbook">
    <style-specification-body>
    
    (define %stylesheet% "stylesheetname.css")
    
    </style-specification-body>
    </style-specification>
    
    <external-specification id="docbook" document="docbook.dsl">
    
    </style-sheet>
    
  • Put your figures in with something like below and you can create both PDF and HTML output

    <figure>
         <title>Figure title</title>
         <mediaobject>
           <imageobject>
             <imagedata fileref="figures/figure.eps" format="EPS" />
           </imageobject>
           <imageobject>
             <imagedata fileref="figures/figure.png" format="PNG" />
           </imageobject>
           <textobject>
             <phrase>About the figure.</phrase>
           </textobject>
         </mediaobject>
       </figure>
    
  • Create your output with the jw wrapper around jade.

    HTML
    $ jw -o html -d stylesheet.dsl -f docbook -b html -l /usr/share/xml/declaration/xml.dcl docbook-file.sgml
    
    PDF
    $ jw -f docbook -b dvi -l /usr/share/xml/declaration/xml.dcl docbook-file.sgml
    $ dvipdf docbook-file.dvi
    

cdecl

cdecl is another tool that has been around since the days when Trumpet Winsock and SLIP were cutting edge (the README says 1996) which I just found a use for.

I find it handy for debugging things like

#include <stdio.h>
#include <setjmp.h>

jmp_buf j;

extern int* fun1(void);
extern int* fun2(void);
extern int* fun3(void);
int* foo(int *p);

int* foo (int *p)
{
    p = fun1();
    if (setjmp (j))
       return p;

       /* longjmp (j) may occur in fun3. */
       p = fun3();
       return p;
}
ianw@lime:/tmp$ gcc -g -c  -O2 -W -Wall -Wstrict-prototypes -Wmissing-prototypes -Werror -g -O3 jmp.c
cc1: warnings being treated as errors
jmp.c: In function 'foo':
jmp.c:11: warning: argument 'p' might be clobbered by 'longjmp' or 'vfork'

I can never remember the correct volatile for this situation

ianw@lime:~$ cdecl
cdecl> explain volatile int *p
declare p as pointer to volatile int
cdecl> explain int *volatile v
declare p as volatile pointer to int

So clearly the second version is the one I want, since I need to indicate that the pointer value might change underneath us. Nifty!

Frodoangelo?

I watched a documentary on Michelangelo the other day, which went into some detail about his David. Despite having seen the real thing, it suddenly struck me how much Frodo from Lord of the Rings looks like him. It's that same pensive "oh shit" look they both seem to have, I think. Or maybe I'm just nuts.

Frodo or David?

how not to print a newline

fputc((int)"\n",fp);

Horus

Our new Sun Fire V20z just arrived, and whilst looking around for the (GPL) source code for the Linux firmware of the onboard PowerPC based managment processor (which can be found by following the download link here), I realised it is just a re-badged Newisys box.

Further investigation lead to an interesting white paper on Horus, a large scale SMP chipset being developed by Newisys (the paper is a bit rough and doesn't appear to have been editied heavily, but worth a read). 4 Opteron processors connect to a Horus chip, which then link to form a larger cache coherent SMP system. Presumably they put four to a chip since four processors is about the sweet spot for the Opteron cache coherency protocol (cHT). Looks like it will scale up to 8-Quads, or 32 processors, talking over Infiniband. Supports dynamic partitioning too. Will be an interesting challenger and worth watching.

To save you looking up Horus he is the Egyptian God of the sun, with the head of a hawk.