How to get the right MIPS libc toolchain for an embedded device

I have a problem (recurring) using embedded Linux products where the GPL source code from them does not match what actually works on the system. This is "close", but not entirely correct, especially with regard to the standard C library they use. Isn't this a GPL violation?

Often this inconsistency leads to the fact that the compiler of the programmer (for example, me) is compiled only for the device to respond critically "file not found" or something similar when the program starts.

I'm not alone with such a problem - there are topics for many people that are directly and indirectly related to the problem: for example: Compile parameters for toolchain based on MIPS code?

And I ran into the problem on Sony devices, D-link and many more. This is very common.

Creating a new library is not a good solution as most systems are ROMFS only and LD_LIBRARY_PATH sometimes breaks, so installing a new library on the device takes up very limited memory and often won't work.

If I knew what the correct version of the library was, I could work around the arbitrary carelessness and compile from the developer source tree; but how can I know which version I need when all I have is the binary of the library itself?

For example: I ran elfread -a libc.so.0 on the libc DSL modem (see below); but I don't see anything here that could tell me which libc it was in ...

How can I find the source code name or ID from a binary library so that I can create a cross compiler using that library? for example: can someone tell me from which source this library came from and how do they know?

ELF Header:
  Magic:   7f 45 4c 46 01 02 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2 complement, big endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              DYN (Shared object file)
  Machine:                           MIPS R3000
  Version:                           0x1
  Entry point address:               0x5a60
  Start of program headers:          52 (bytes into file)
  Start of section headers:          0 (bytes into file)
  Flags:                             0x1007, noreorder, pic, cpic, o32, mips1
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         4
  Size of section headers:           0 (bytes)
  Number of section headers:         0
  Section header string table index: 0

There are no sections in this file.

There are no sections to group in this file.

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  REGINFO        0x0000b4 0x000000b4 0x000000b4 0x00018 0x00018 R   0x4
  LOAD           0x000000 0x00000000 0x00000000 0x2c9ee 0x2c9ee R E 0x1000
  LOAD           0x02c9f0 0x0006c9f0 0x0006c9f0 0x009a0 0x040b8 RW  0x1000
  DYNAMIC        0x0000cc 0x000000cc 0x000000cc 0x0579a 0x0579a RWE 0x4

Dynamic section at offset 0xcc contains 19 entries:
  Tag        Type                         Name/Value
 0x0000000e (SONAME)                     Library soname: [libc.so.0]
 0x00000004 (HASH)                       0x18c
 0x00000005 (STRTAB)                     0x3e9c
 0x00000006 (SYMTAB)                     0x144c
 0x0000000a (STRSZ)                      6602 (bytes)
 0x0000000b (SYMENT)                     16 (bytes)
 0x00000015 (DEBUG)                      0x0
 0x00000003 (PLTGOT)                     0x6ce20
 0x00000011 (REL)                        0x5868
 0x00000012 (RELSZ)                      504 (bytes)
 0x00000013 (RELENT)                     8 (bytes)
 0x70000001 (MIPS_RLD_VERSION)           1
 0x70000005 (MIPS_FLAGS)                 NOTPOT
 0x70000006 (MIPS_BASE_ADDRESS)          0x0
 0x7000000a (MIPS_LOCAL_GOTNO)           11
 0x70000011 (MIPS_SYMTABNO)              677
 0x70000012 (MIPS_UNREFEXTNO)            17
 0x70000013 (MIPS_GOTSYM)                0x154
 0x00000000 (NULL)                       0x0

There are no relocations in this file.

The decoding of unwind sections for machine type MIPS R3000 is not currently supported.

Histogram for bucket list length (total of 521 buckets):
 Length  Number     % of total  Coverage
      0  144        ( 27.6%)
      1  181        ( 34.7%)     27.1%
      2  130        ( 25.0%)     66.0%
      3  47         (  9.0%)     87.1%
      4  12         (  2.3%)     94.3%
      5  5          (  1.0%)     98.1%
      6  1          (  0.2%)     99.0%
      7  1          (  0.2%)    100.0%

No version information found in this file.

Primary GOT:
 Canonical gp value: 00074e10

 Reserved entries:
   Address     Access  Initial Purpose
  0006ce20 -32752(gp) 00000000 Lazy resolver
  0006ce24 -32748(gp) 80000000 Module pointer (GNU extension)

 Local entries:
   Address     Access  Initial
  0006ce28 -32744(gp) 00070000
  0006ce2c -32740(gp) 00030000
  0006ce30 -32736(gp) 00000000
  0006ce34 -32732(gp) 00010000
  0006ce38 -32728(gp) 0006d810
  0006ce3c -32724(gp) 0006d814
  0006ce40 -32720(gp) 00020000
  0006ce44 -32716(gp) 00000000
  0006ce48 -32712(gp) 00000000

 Global entries:
   Address     Access  Initial Sym.Val. Type    Ndx Name
  0006ce4c -32708(gp) 000186c0 000186c0 FUNC    bad section index[  6] __fputc_unlocked
  0006ce50 -32704(gp) 000211a4 000211a4 FUNC    bad section index[  6] sigprocmask
  0006ce54 -32700(gp) 0001e2b4 0001e2b4 FUNC    bad section index[  6] free
  0006ce58 -32696(gp) 00026940 00026940 FUNC    bad section index[  6] raise
  ...
  truncated listing
  ....

      


Note: The rest of this post is a blog showing how I came to ask the question above and put useful information about the subject in one place. Don't bother reading if you don't want to know that I actually researched the question ... in detail ... and how NOT to answer my question.

The correct (theoretical) way to get the libc program running (for example), the D-link modem is just to get the TRUE source code for the product from the manufacturer and compile it with those libraries .... (It's GPL !? Right, so the law is on ours side, right?)

For example: I just bought a D-Link DSL-520B modem and a 526B modem, but found out after the manufacturer "forgot" to provide the Linux source code for the 520B but has it for the 526B. I checked all DSL-5xxB devices on the internet for source code and toolchains, in my opinion ALL of them (including 526B) contain the MOST precompiled libc.so.0 with MD5sum 6ed709113ce615e9f170aafa0eac04a6. So in theory, all supported modems of the DSL-5xxB family seem to use the same libc ... and I was hoping I could use that library.

But after I figured out how to get the DSL modem itself to send me a copy of the installed library /lib/libc.so.0, I found that they ALL use the library with MD5 sum b8d492decc8207e724a0822641205078, IN NEITHER modems that I bought (supported or not), the same libraries were found as contained in the source toolchain.

To check if the toolchain from D-link is corrupted, I didn't compile the program (the toolchain won't work on my PC anyway, as it was the wrong binary format), but I found that there are some pre-compiled in the toolchain the mips binaries are already in it; so I just loaded it into my modem and chmod + x - and (unexpectedly) got a file not found message. when i tried to run it ... it wont work.

So, I knew that toolchains didn't fit right away, but not really.

I decided to get a newer version of MIPS GCC (binary), which should have fewer bugs, more features and is supported on most PC platforms. This is the GO!

See: Kernel.org Precompiled Binaries

I upgraded to gcc 4.9.0 after selecting the older "mips" verson from the above site to get the FTP page I wanted; and set the PATH variable of my shell to the cross compiler / bin directory after installation.

Then I copied all the header and library files from the D-link source code to the new cross compiler to make sure it can compile the D-link lib binaries. And that was on the first try, making up "hello world!" without any warnings or errors into binary 32 large binary.

( START EDITING:) @ChrisStratton notes in the comments (following this post) that my toolchain test is inadequate, and that using newer GCC with an older library, even if linked correctly, is erroneous as a test. I wish he would give him points for his comments - I made sure he was right; although this does what D-link does an even worse problem, as there is no way of knowing from the modem binaries which GCC they were actually using. The GCC used for the kernel is not necessarily used in user space.

To test the compatibility of the new compiler with modems, and also make tools so that I can get a copy of the actual libraries found on the modem: ( END EDIT ) I wrote a program that doesn't use the C library at all (but in two parts) : it just ended ... and the code is attached to show how it can be done.

The first list is an assembly language program for bypassing references to standard C libraries on MIPS; and the second enum is a program designed to dump the octal number of a binary file / stream using only linux kernel. for example: it allows you to copy / paste or write binary data over telnet, netcat, etc. via ash / bash or busybox :) as an awkward uucp user.

// substart.S  MIPS assembly language bypass of libc startup code       
// it just calls main, and then jumps to the exit function       

            .text                                                               
            .globl __start                                                      
__start:    .ent    __start                                                     
            .frame  $29, 32, $31                                                
            .set noreorder                                                       
            .cpload $25                                                         
            .set reorder                                                        
            .cprestore 16                                                       

            jal main                                                            
            j   exit                                                            

            .end    __start                                                     
// end substart.S                          

      

... and ...

// octdump.c
// To compile w/o libc :                                                                   
// mips-linux-gcc stubstart.S octdump.c -nostdlib -o octdump

// To compile with working libc (eg: x86 system) :
// gcc octdump.c -o octdump_x86         

#include <syscall.h>                                                            
#include <errno.h>                                                              
#include <sys/types.h>                                                          

int* __errno_location(void) { return &errno; }                                  

#ifdef _syscall1
// define three unix functions (exit,read,write) in terms of unix syscall macros.
_syscall1( void, exit, int, status );                                           
_syscall3( ssize_t, read, int, fd, void*, buf, size_t, count );                 
_syscall3( ssize_t, write, int, fd, const void*, buf, size_t, count );          
#endif                

#include <unistd.h>                                                             

void oct( unsigned char c ) {                                                   
    unsigned int n = c;                                                         
    int m=6;                                                                    
    static unsigned char oval[6]={'\\','\\','0','0','0','0'};                   
    if (n < 64) { m-=1; n <<= 3; }                                              
    if (n < 64) { m-=1; n <<= 3; }                                              
    if (n < 64) { m-=1; n <<= 3; }                                              

    oval[5]='0'+(n&7);                                                          
    oval[4]='0'+((n>>3)&7);                                                     
    oval[3]='0'+((n>>6)&7);                                                     
    write( STDOUT_FILENO, oval, m );                                            
}                                                              

int main(void) {                                                                
    char buffer[255];                                                           
    int count=1;                                                                
    int i;                                                                      

    while (count>0) {                                                           
        count=read( STDIN_FILENO, buffer, 17 );                                 
        if (count>0) write( STDOUT_FILENO, "echo -ne $'",11 );                  
        for (i=0; i<count; ++i) oct( buffer[i] );                               
        if (count>0) write( STDOUT_FILENO, "'\n", 2 );                          
    }                                                                           
    write( STDOUT_FILENO,"#\n",2);                                              
    return 0;                                                                   
}                     

      

Once mcts octdump was saved (chmod + x) as / var / octdump on the modem, it worked without error. (use your imagination on how I got it there ... Dlink TFTP and friends are broken.)

I was able to use octdump to copy all dynamic link libraries from DSL modem and examine them with an automated script to avoid manual copy / paste.

#!/bin/env python                                                               
# octget.py                                                                     
# A program to upload a file off an embedded linux device via telnet                      
import socket                                                                   
import time                                                                     
import sys                                                                      
import string                                                                   

if len( sys.argv ) != 4 :                                                       
    raise ValueError, "Usage: octget.py IP_OF_MODEM passwd path_to_file_to_get" 

o = socket.socket( socket.AF_INET, socket.SOCK_STREAM )                         
o.connect((sys.argv[1],23)) # The IP address of the DSL modem.                  
time.sleep(1)                                                                   
sys.stderr.write( o.recv(1024) )                                                
o.send("admin\r\n");                                                            
time.sleep(0.1)                                                                 
sys.stderr.write( o.recv(1024) )                                                
o.send(sys.argv[2]+"\r\n")                                                      
time.sleep(0.1)                                                                 
o.send("sh\r\n")                                                                
time.sleep(0.1)                                                                 
sys.stderr.write( o.recv(1024) )                                                
o.send("cd /var\r\n")                                                           
time.sleep(0.1)                                                                 
sys.stderr.write( o.recv(1024) )                                                
o.send("./octdump.x < "+sys.argv[3]+"\r\n" );                                   
sys.stderr.write( o.recv(21) )                                                  
get="y"                                                                         
while get and not ('#' in get):                                                 
    get = o.recv(4096)                                                          
    get = get.translate( None, '\r' )                                           
    sys.stdout.write( get )                                                     
    time.sleep(0.5)                                                             
o.close()  

      

The DSL520B modem had the following libraries ... libcrypt.so.0 libpsi.so libutil.so.0 ld-uClibc.so.0 libc.so.0 libdl.so.0 libpsixml.so

... and I thought I could compile these libraries ever since (at least in theory) - GCC can link to them; and my problem can be solved.

I am very confident that I will remove all incompatible .so libraries from gcc-4.9.0 / mips-linux / mips-linux / lib, but kept the common crt..o files; then I copied the modem libraries into the cross compiler directory.

But even though the kernel version of the kernel source and the kernel version of the matched modem - GCC found undefined characters in the crt files .... So either the shared crt files or the modem libraries themselves are somehow incomplete ... and I am not I know why. Not knowing how to get the full version of the library? ucLibc? library, I'm not sure how I can get the source code of CORRECT to recompile libraries and crt from scratch.

+3


source to share





All Articles