This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Create a dynamically linkable library



Hi everyone,

I try to build a dynamically linkable library using the C6000 CGT (from CCS v5).

For example, I created the simplest source file:

/* hello.c */
#include <stdio.h>
__declspec(dllexport) int hello(int a, int b);

int hello(int a, int b)
{
int result = b - a;
printf("Hello World, %d\n", result);
return result;
}

After this, I tried to build the file using gmake utility with --dynamic=lib option set. But I observed the following error message:

 undefined first referenced
symbol in file
--------- ----------------
printf hello.obj

error: unresolved symbols remain
error: errors encountered during linking; "hello.dll" not built

But as I think, the printf function should be linked dynamically.

Linked libc.a (with --library=libc.a option set) the file is built successfully but the output binary file contains printf and many other function from libc.a. So, the size of the output file is large.

But it seems like the output file's size should be reduced using dynamic linking of libraries. What is wrong in my approach?

Regards,

Nikolay

  •  

    Hi Nikolay,

    There is nothing wrong with your approach, except that you are calling printf() which calls quite a few other functions that are defined in the RTS library. That is why your resulting dynamic library includes so much other stuff.

    If you are truly starting from scratch, a good approach to take is to build your dynamic libraries from the bottom (of the call graph) up.

    For example, consider that you have several leaf functions that are commonly used by several other dynamic libraries. You can collect the leaf functions into their own dynamic library (leaves.dll): The sources containing the definitions of the leaf functions should export the leaf function symbols (just like you do in your 'hello' source above).

    cl6x --abi=eabi --mem_model:data=far -mv64+ leaf1.c leaf2,c leaf3.c -z  --dynamic=lib -o leaves.dll

    Now, suppose you have other groups of functions (limb_1*.c and limb_2*.c) that use the leaf functions from leaves.dll and you want to create dynamic libraries out of them ...

    cl6x .--abi=eabi --mem_model:data=far -mv64+ limb_1a.c limb_1b.c limb_1c.c -z  --dynamic=lib leaves.dll -o limb_1.dll

    cl6x --abi=eabi --mem_model:data=far -mv64+ limb_2a.c limb_2b.c -z  --dynamic=lib leaves.dll -o limb_2.dll

    Note that leaves.dll is specified as an input to the static link step that builds limb_1.dll and limb_2.dll. This is because the calls to the leaf functions from limb_1.dll and limb_2.dll must be resolved at static link time. The specification of leaves.dll during the link step of the build of limb_1.dll and limb_2.dll does not have any impact on the size of limb_1.dll or limb_2.dll. In fact, you will see an overall size savings since the defintions of the leaf functions will only be in leaves.dll, not in limb_1.dll or limb_2.dll.

    I hope this helps. Please don't hesitate to ask if you have further questions or need clarification.

    Thanks and Regards,

    Todd Snider

    C6000 Code Generation Tools Team

    Texas Instruments Incorporated

  • Hi Todd,

    Thank you for your detailed answer. I agree with what you wrote...

    Let me do a small preamble. I want to use RIDL (dynamic loader) on the my design. So, I added source code of the RIDL in the my RTCS project and successfully built a core image from it. Now I want to create a dll which will be use some functions from my RTCS project image (i.e. from my core image).

    Because core image contains an C-runtime functions and also my other functions, I think that described above dll must not contain any of these functions.

    How can I to specify the linker what my dll must be dynamically linked into core image?

    Also I have a other question: Why when I build a dll with --dynamic=lib option then I do not have the  .args section? If setting up  --dynamic=exe option then the .args section is available.

    Regards, Nikolay

  • Todd,

    I tried to build my hello.c with following options as described above:

    cl6x --abi=eabi --mem_model:data=far -mv64+ hello.c  -z  --dynamic=lib ritl.out -o hello.dll -m hello.map

    where ritl.out a base image after build RIDL.

    You can see MAP file contains an referenced of ridl.out and hello.dll has increase size.

    8360.hello.map.zip

    You can help me for resolve this issue?

    Thanks

  •  

    Hello Nikolay,

    I'm sorry for the delay in responding. Let me address your post from 22 March first. If that does not shed some light on your later questions, we can continue the discussion.

    One thing that I'd like to point out about RIDL is that it is a "reference implementation" of the dynamic loader. It is intended to be a demonstration of the interface between the client side of the dynamic loader and what we call the dynamic loader "core". The core contains code that knows about the details of the ELF object format (ELF file header, program header table, section table, etc.). 

    The boundary between the client side and the dynamic loader core is described in the header file, dload_api.h. Any functions that begin with a "DLOAD_" prefix are supplied in the core. Functions which begin with a "DLIF_" prefix are expected to be supplied by the client side implementation. The core part of the dynamic loader is partable from platform to platform, but the client side implementation will vary based on what the needs are for a given platform. In the case of RIDL, the client is implemented as an executable that can be loaded onto the target and run. When it runs, it will bring up a simplistic user interface that allows you to dynamically load and run DLLs that have been linked against the RIDL dynamic executable. For example,

    cl6x -mv64+ --abi=eabi --mem_model:data=far hello.c -z --dynamic=lib ridl.exe -e start -o hello.dll

    builds a dynamic library, hello.dll, which can call functions that are exported by ridl.exe. The "-e start" option defines the function start() in hello.c to be the entry point at which you want to start execiution when hello.dll is load and run from the RIDL user interface. To load and run hello.dll, you would first load and run ridl.exe at which point the RIDL user interface would come up. Using the RIDL user interface, you then load the symbols from ridl.exe with the "base_image" command. Then you can load your hello.dll dynamic library with the "load" command. Finally, you can run the hello.dll code from its entry point (start) using the "exec" command. To get out of the RIDL user interface and terminate the execution of ridl.exe, you can specify the "exit" command from the RIDL user interface.

    With all of that said, I suspect that you don't intend for the dynamic loader in your system to work like RIDL. In which case, you will likely need to create your own implementation of the client side of the dynamic loader.

    If you could provide a clearer picture of how you envision your system architecture and how all of the pieces interact with each other, I may be able to help point you in the right direction.

    For example, if you want the dynamic loader to be able to load and run a dynamic executable, then you will need to implement a client side of the dynamic loader which can handle the .args section of the dynamic executable that is to be loaded and run. Other question to consider ... Do you want to run the dynamic loader on the target or on the host system? Do you have an OS running on the target that will initiate the dynamic loader?

    Regards,

    Todd

  • In reply to your question from 26 March ... If you want to run hello.dll code from RIDL, you will want to define an entry point for hello.dll (not main(); you could just rename main() in hello.c to start() and then use "-e start" on the above linker command line).

    - Todd

  • Hello Todd,

    Thanks for answering about RIDL, it was very detailed and clear. But I wanted to ask you about dynamic linking.

    So, you write:

    >cl6x -mv64+ --abi=eabi --mem_model:data=far hello.c -z --dynamic=lib ridl.exe -e start -o hello.dll

    >builds a dynamic library, hello.dll, which can call functions that are exported by ridl.exe

    I tried to do it in my example (in my first post), but hello.dll DOESN'T use the functions exported ridl  (such as printf).

    Thus all functions exported by ridl have been statically linked into hello.dll (see hello.map file attached above in my post). I.e. the generated dll contains many functions from ridl image and don't have any imported functions.

    I don't understand the reasons for this result.

    Regards, Nikolay

    PS: I use the evmomap-l137 platform, and the ridl (well-known as core and client) are running in the dsp side under sys/bios.

  • Hi Nikolay,

    In the test example that I am working with, the hello.c file contains an export of the startt symbol and an import of the printf symbol:

    #include <stdio>

    __declspec(dllexport) int start();

    __declspec(dllimport) int printf(const char *_format, ...);

    int start()

    {

       printf("PASS - hello.c\n");

       return 0;

    }

    Perhaps the detail that I neglected to mention is that you need to import functions that you want to call from a DLL. Similarly, you'll want to export functions that you want to be callable from your DLL.

    - Todd

  • Todd,

    It's simple and clear. I think what you do not understand me fully or what I can not explain a question :)

    With same compiler options as described above, I get a statically link for all functions which must be imported.

    For example, in our case, the printf function must be IMPORTED from ridl image. But this function as I can see from the map-file has static link and the dll-file not contains any imported functions.

    ******************************************************************************
    TMS320C6x Linker PC v7.3.1
    ******************************************************************************
    >> Linked Fri Mar 30 22:30:48 2012

    OUTPUT FILE NAME: <hello.dll>
    ENTRY POINT SYMBOL: "start" address: c0010e40


    MEMORY CONFIGURATION

    name origin length used unused attr fill
    ---------------------- -------- --------- -------- -------- ---- --------
    DSPRAM 11800000 00040000 00000000 00040000 RWIX
    SHAREDRAM 80000000 00020000 00000010 0001fff0 RWIX
    SDRAM c0000000 20000000 00010e60 1ffef1a0 RWIX
    VECS ffff0000 00000080 00000000 00000080 RWIX
    ARMRAM ffff0080 00001f80 00000000 00001f80 RWIX


    SEGMENT ALLOCATION MAP

    run origin load origin length init length attrs members
    ---------- ----------- ---------- ----------- ----- -------
    80000000 80000000 00000010 00000010 r--
    80000000 80000000 00000010 00000010 r-- .const
    c0000000 c0000000 00010e60 00010e60 r-x
    c0000000 c0000000 00010e60 00010e60 r-x .text


    SECTION ALLOCATION MAP

    output attributes/
    section page origin length input sections
    -------- ---- ---------- ---------- ----------------
    .cinit 0 80000000 00000000 UNINITIALIZED

    .const 0 80000000 00000010
    80000000 00000010 hello.obj (.const)

    .text 0 c0000000 00010e60
    c0000000 00010e40 RIDL.out (.text)
    c0010e40 00000020 hello.obj (.text)
    GLOBAL SYMBOLS: SORTED ALPHABETICALLY BY Name 
    .....
    [205 symbols]


    DYNAMIC SYMBOLS: SORTED ALPHABETICALLY BY Name
    .....
    [7 symbols]


    IMPORTED and EXPORTED SYMBOLS: SORTED ALPHABETICALLY BY Name

    IMPORTED SYMBOLS

    name size Imported from
    ----------------------------- -------- -------------

    [0 symbols]


    EXPORTED SYMBOLS

    address name
    -------- ----
    c0010e40 start

    Why is this happening?

    Regards, Nikolay

  •  

    Nikolay,

    I am not seeing the same results as you are in a simple "hello" type example:

    >> Linked Fri Mar 30 14:10:32 2012

    OUTPUT FILE NAME: <hello.dll>

    ENTRY POINT SYMBOL: "start" address: 00000040

     

    MEMORY CONFIGURATION

    name origin length used unused attr fill

    ---------------------- -------- --------- -------- -------- ---- --------

    RAM 00000020 ffffffe0 00000080 ffffff60 RWIX

     

    SEGMENT ALLOCATION MAP

    run origin load origin length init length attrs members

    ---------- ----------- ---------- ----------- ----- -------

    00000020 00000020 00000070 00000070 r-x

    00000020 00000020 00000020 00000020 r-x .plt

    00000040 00000040 00000040 00000040 r-x .text

    00000080 00000080 00000010 00000010 r-- .const:.string

     

    SECTION ALLOCATION MAP

    output attributes/

    section page origin length input sections

    -------- ---- ---------- ---------- ----------------

    .plt 0 00000020 00000020

    00000020 00000020 (.plt.printf)

    .text 0 00000040 00000040

    00000040 00000040 hello.obj (.text)

    .const:.string

    * 0 00000080 00000010

    00000080 00000010 hello.obj (.const:.string)

     

    PROCEDURE LINKAGE TABLE

    PLT entry name /

    addr procedure name

    -------- ------------------------

    00000020 .plt.printf

    printf

     

    GLOBAL SYMBOLS: SORTED ALPHABETICALLY BY Name

    address name

    -------- ----

    00000020 .plt.printf

    00000000 __TI_STATIC_BASE

    ffffffff __TI_pprof_out_hndl

    ffffffff __TI_prof_data_size

    ffffffff __TI_prof_data_start

    UNDEFED printf

    00000040 start

     

    GLOBAL SYMBOLS: SORTED BY Symbol Address

    address name

    -------- ----

    00000000 __TI_STATIC_BASE

    00000020 .plt.printf

    00000040 start

    ffffffff __TI_pprof_out_hndl

    ffffffff __TI_prof_data_size

    ffffffff __TI_prof_data_start

    UNDEFED printf

    [8 symbols]

     

    DYNAMIC SYMBOLS: SORTED ALPHABETICALLY BY Name

    address name

    -------- ----

    UNDEFED

    0000005c $C$RL0

    00000080 $C$SL1

    00000000 __TI_STATIC_BASE

    ffffffff __TI_pprof_out_hndl

    ffffffff __TI_prof_data_size

    ffffffff __TI_prof_data_start

    UNDEFED printf

    00000040 start

    [9 symbols]

     

    IMPORTED and EXPORTED SYMBOLS: SORTED ALPHABETICALLY BY Name

    IMPORTED SYMBOLS

    name size Imported from

    ----------------------------- -------- -------------

    printf unified_dyn_loader/dlti.gen

     

    EXPORTED SYMBOLS

    address name

    -------- ----

    00000040 start

    Do you still have a definition of main() in your hello.c file? If so, this will cause the linker to pull in many of the things that are already in ridl.out (dlti.gen in my example) when building hello.dll.

    There is certainly something amiss between your example and my example. Another source of information about what is happening during the link step is to look at the ofd6x output for hello.dll. ofd6x is an object file dump utility which gives you a more readable display of what is actually in the output file produced by the link. For example, if I run "ofd6x -v hello.dll > hello_ofd.txt" on my example, I get a file which includes the following snippet:

    Dynamic Information in ".dynamic"

    id tag value

    -- --- -----

    0 DT_NEEDED dlti.gen

    1 DT_PLTRELSZ 0

    2 DT_HASH 0x00001164

    3 DT_STRTAB 0x000010e4

    4 DT_SYMTAB 0x00001054

    5 DT_RELA 0x00000168

    6 DT_RELASZ 72

    7 DT_RELAENT 12

    8 DT_STRSZ 125

    9 DT_SYMENT 16

    10 DT_SONAME hello.dll

    11 DT_PLTREL 7

    12 DT_TEXTREL

    13 DT_JMPREL 0x000001b0

    14 DT_BIND_NOW

    15 DT_FLAGS 12

    16 DT_C6000_GSYM_OFFSET 112

    17 DT_C6000_GSTR_OFFSET 93

    18 DT_NULL

    19 DT_NULL

    20 DT_NULL

    21 DT_NULL

    22 DT_NULL

    The DT_NEEDED dynamic tag above indicates that there is a dependency between hello.dll and dlti.gen (the base image of the dynamic loader). You should see something similar in the ofd6x output for your example hello.dll.

    If this still doesn't help to solve your problem, can you write down the details of your build steps and describe exactly what you expect to see at the conclusion of each step? This might help to illuminate to me where our examples are diverging in behavior.

    - Todd

  • Hi Todd,

    I checked  reasons which you a said, but it did not help. I attach the  hello source and makefile below:

    3438.hello.zip

    Thanks

  •  

    Nikolay,

    It looks like the difference between my example and yours is the dynamic loader itself.

    In your RIDL.map, there are no exported symbols, so printf cannot be imported by hello.c (this is why it is linking against the RTS again).

    In a map file generated from my build of the dynamic loader base image file (dlti.gen), I have the following exported symbols:

    IMPORTED and EXPORTED SYMBOLS: SORTED ALPHABETICALLY BY Name

    IMPORTED SYMBOLS

    name size Imported from

    ----------------------------- -------- -------------

    [0 symbols]

     

    EXPORTED SYMBOLS

    address name

    -------- ----

    0002165c _DLModules

    0001ea40 __c6xabi_cmpd

    00020cc0 __c6xabi_cvtfd

    0001df60 __c6xabi_divi

    0001ffa0 __c6xabi_divu

    000208c0 __c6xabi_llshru

    0001eb40 __c6xabi_remi

    00020320 __c6xabi_remu

    00020e40 __c6xabi_subd

    00020fa0 __c6xabi_subf

    00021080 __cxa_atexit

    0001de40 __cxa_finalize

    902017ac _ctypes_

    000211c0 clock

    0001fa80 exit

    90202384 export_var

    000209c0 fclose

    00020500 fopen

    00018620 fread

    00019520 free

    0001c220 ftell

    00014ec0 fwrite

    000211e0 getenv

    0001fb60 ltoa

    0001b980 malloc

    0001bbc0 memcpy

    0001b2a0 open

    0001e620 printf

    00020bc0 strcmp

    0001fe00 strstr

    Please take a closer look at your build of RIDL.out to be sure you are exporting symbols (the RIDL package should contain a c60_export.cmd file that should be included in the link command of the RIDL.out build). Your RIDL.out also does not contain a .dynamic section which indicates that you did not build it with the --dynamic=exe option in the link command.

    Hope this is helpful.

    - Todd

  • Hi Todd,

    I did not know about --dynamic=exe option for building the ridl. Now, after rebuild with this option, hello example are used imported functions.

    Thanks for you support.

    Regards Nikolay