Where is the relocation information in the ELF format? - linux

Quoting "Linkers and Loaders" in the Loaders part
"load-time relocation is far simpler than link-time relocation,
because the entire program is relocated as a unit. [...]
After reading the program into memory, the loader consults
the relocation items in the object file and fixes up the memory
locations to which the items point"
Maybe I misunderstood this point and this is only in some architectures, but my question is: where in the ELF format is specified which items need relocation at load time? how can I inquire for this list?

Relocations are to be found in special relocation sections in the ELF file. You can use the readelf --sections command to find out what sections are there in an executable or a shared library and those of type REL contain relocation instructions. The content of those relocation sections can be displayed using readelf --relocs. For example:
$ readelf --relocs /bin/ls
Relocation section '.rela.dyn' at offset 0x16c8 contains 5 entries:
Offset Info Type Sym. Value Sym. Name + Addend
00000061afd8 000c00000006 R_X86_64_GLOB_DAT 0000000000000000 __gmon_start__ + 0
00000061b540 006d00000005 R_X86_64_COPY 000000000061b540 optind + 0
00000061b548 006e00000005 R_X86_64_COPY 000000000061b548 optarg + 0
00000061b550 006a00000005 R_X86_64_COPY 000000000061b550 stderr + 0
00000061b560 006600000005 R_X86_64_COPY 000000000061b560 stdout + 0
Relocation section '.rela.plt' at offset 0x1740 contains 99 entries:
Offset Info Type Sym. Value Sym. Name + Addend
00000061b000 000100000007 R_X86_64_JUMP_SLO 0000000000000000 strcoll + 0
00000061b008 000200000007 R_X86_64_JUMP_SLO 0000000000000000 mktime + 0
...
The .rela.dyn section contains references to references in the program's code of code or data symbols that have to be relocated at load time while .rela.plt contains mostly jump slots that are used to call functions in shared objects. Note that usually only shared objects are compiled as position-independent code while the usual executables are not. This is due to the fact that PIC code is a bit slower than non-PIC code.

Related

how to make use the .rela.dyn to trigger elf loader for aarch64?

I have implemented packer of x86_64 shared library.
Briefly,
a simple xor-loader is injected to a shared library (by creating a new section)
the rela.dyn act as an entrypoint for the shared library
the rela.dyn entry is patched such that it points to the address of the loader.
once the shared library is called, the xor-loader is triggered and decrypt the .text section.
The mechanism works fine for the x86_64 shared library.
The rela.dyn tricks is borrowed from
https://github.com/0xN3utr0n/Noteme/blob/master/injection.c
However, this mechanism failed on aarch64.
I found that
if I xor-ed the .text section, the xor-loader is bypassed
I got Illegal instruction (core dumped), since the .text section has not been decrypted by the xor-loader. (confirmed by inspecting the .text section by gdb)
I have the loader objdump-ed, the loader is intact.
if I don't xor the .text section, the xor-loader is called and work normally. (But the decryption is wrong, since the .text section has not been xor-ed beforehand).
Question:
What could have possible went wrong in aarch64 ?
The result of readelf for aarch64 shared library is provided below.
libtest.so is the library before packing.
While libtest_packed.so is the library after packing.
Here is the result of readelf --relocs libtest.so
Relocation section '.rela.dyn' at offset 0x550 contains 7 entries:
000000010df0 000000000403 R_AARCH64_RELATIV 780
000000010df8 000000000403 R_AARCH64_RELATIV 738
000000011018 000000000403 R_AARCH64_RELATIV 11018
000000010fc8 000300000401 R_AARCH64_GLOB_DA 0000000000000000 _ITM_deregisterTMClone + 0
000000010fd0 000400000401 R_AARCH64_GLOB_DA 0000000000000000 __cxa_finalize#GLIBC_2.17 + 0
000000010fd8 000500000401 R_AARCH64_GLOB_DA 0000000000000000 __gmon_start__ + 0
000000010fe0 000700000401 R_AARCH64_GLOB_DA 0000000000000000 _ITM_registerTMCloneTa + 0
the functions corresponding to the first 3 entries are:
0000000000000780 t frame_dummy
0000000000000738 t __do_global_dtors_aux
000000000011018 d __dso_handle
here is the result of readelf --relocs libtest_packed.so
Relocation section '.rela.dyn' at offset 0x550 contains 7 entries:
Offset Info Type Sym. Value Sym. Name + Addend
000000010df0 000000000403 R_AARCH64_RELATIV 11028
000000010df8 000000000403 R_AARCH64_RELATIV 738
000000011018 000000000403 R_AARCH64_RELATIV 11018
000000010fc8 000300000401 R_AARCH64_GLOB_DA 0000000000000000 _ITM_deregisterTMClone + 0
000000010fd0 000400000401 R_AARCH64_GLOB_DA 0000000000000000 __cxa_finalize#GLIBC_2.17 + 0
000000010fd8 000500000401 R_AARCH64_GLOB_DA 0000000000000000 __gmon_start__ + 0
000000010fe0 000700000401 R_AARCH64_GLOB_DA 0000000000000000 _ITM_registerTMCloneTa + 0
As you can see, the first entry is overwritten by the address of the loader.

Multiple global offset tables in linux process

I'm examining memory layout of a running process and made an interesting observation. There seems to be multiple GOTs (global offset table). Here is what I see in the debugger when I study a malloc function:
(gdb) p (void *) 0x7ff5806ae020
$5 = (void *) 0x7ff5806ae020 <malloc#got.plt>
(gdb) p (void *) 0x7ff5806471d0
$6 = (void *) 0x7ff5806471d0 <malloc#got.plt>
(gdb) p (void *) 0x5634ef446030
$7 = (void *) 0x5634ef446030 <malloc#got.plt>
I examine 3 different addresses of a malloc trampoline. When I look at the memory maps of the process, these addresses correspond to following entries:
7ff580647000-7ff580648000 rw-p 0001c000 fd:01 547076 /lib/x86_64-linux-gnu/libpthread-2.31.so
5634ef446000-5634ef447000 rw-p 00003000 fd:02 12248955 /home/user/binary
7ff5806ae000-7ff5806af000 rw-p 0002a000 fd:01 523810 /lib/x86_64-linux-gnu/ld-2.31.so
I see the different entries correspond to different "linkable objects": the binary and two dynamic libraries.
Further, two out of three trampolines point to the actual function. And both the pointers are the same. The third trampoline points to the stub.
(gdb) p *(void **) 0x5634ef446030
$8 = (void *) 0x7ff5804ef1b0 <__GI___libc_malloc>
(gdb) p *(void **) 0x7ff5806471d0
$9 = (void *) 0x7ff580631396 <malloc#plt+6>
(gdb) p *(void **) 0x7ff5806ae020
$10 = (void *) 0x7ff5804ef1b0 <__GI___libc_malloc>
Is there really a need for three trampolines? If yes, then why?
I realised that such system is the only sensible way to implement trampolines.
In assembly, each call instruction to a dynamically linked function basically refers to an index of the function in GOT. The index is encoded in the instruction directly. Therefore, the index must be known the latest during static linkage. Otherwise, the program code must be updated by the dynamic linker each time the program starts. Clearly, very cumbersome task.
Moreover, each library is compiled separately, therefore must not depend on other libraries, including their exact GOT layout. If there was a single GOT, then all libraries that loaded together must somehow agree on the meanings of each entry in GOT. Having a shared data structure (GOT), filled by all libraries together, would almost certainly create such a dependency.
For example, readelf says that .so-files also have got table:
$ readelf -S /lib/ld-linux.so.2
[18] .got PROGBITS 00029ff4 028ff4 000008 04 WA 0 0 4
[19] .got.plt PROGBITS 0002a000 029000 000028 04 WA 0 0 4
$ readelf -S /usr/lib/libpurple.so.0.13.0
[21] .got PROGBITS 0000000000137318 00136318
0000000000003cd8 0000000000000008 WA 0 0 8
Although, libpurple does not have .got.plt, which I don't fully understand.
My confusion was coming from a fact that the table is called "global". The word "global" actually means that the table is global at the level of a linkable object, in contrast to a compilation module (.o files).
Second, I had an illusion that GOT is referred to an executable application, instead of any dynamically linkable object.

Reading ELF header of loaded shared object during runtime

I wrote some code to search for a symbol in a shared library's ELF header. The code works if I parse the shared object file stored on my disk.
Now, I wanted to use this code to parse the ELF header of a loaded shared library. As an example the libdl library is mapped into the current process:
b7735000-b7738000 r-xp 00000000 08:01 315560 /lib/i386-linux-gnu/libdl.so.2
b7738000-b7739000 r--p 00002000 08:01 315560 /lib/i386-linux-gnu/libdl.so.2
b7739000-b773a000 rw-p 00003000 08:01 315560 /lib/i386-linux-gnu/libdl.so.2
The (first) mapping of the address contains the ELF header. I tried to read this header and to extract the dlopen symbol in the .dynsym section. However, the header is slightly different from the one of the 'plain' .so file on the disk. For example the offset of the .shstrtab version is 0. Therefore, it is not possible to get the name of a section.
I wanted to ask why the ELF header is changed during loading of the library and where I can find the 'missing' sections. Is it even possible to parse the ELF header after the library was loaded?
Does anybody know any article explaining the layout of a shared library/its ELF header when it is mapped into a process?
Currently I'm using following functions to iterate over the ELF header. If libdl_start points to the memory mapped libdl.so.2 file, the code works fine. However, if it points to the region mapped by the linker, get_dynstr_section does not find the dynstr section.
int get_libdl_functions()
{
Elf32_Ehdr *ehdr = libdl_start;
Elf32_Shdr *shdr, *shdrs_start = (Elf32_Shdr *)(((char *)ehdr) + ehdr->e_shoff);
Elf32_Sym *symbol, *symbols_start;
char *strtab = get_dynstr_section();
int sec_it = 0, sym_it = 0;
rt_info->dlopen = NULL;
rt_info->dlsym = NULL;
if(strtab == NULL)
return -1;
for(sec_it = 0; sec_it < ehdr->e_shnum; ++sec_it) {
// Iterate over all sections to find .dynsym
shdr = shdrs_start + sec_it;
if(shdr->sh_type == SHT_DYNSYM)
{
// Ok we found the right section
symbols_start = (Elf32_Sym *)(((char *)ehdr) + shdr->sh_offset);
for(sym_it = 0; sym_it < shdr->sh_size / sizeof(Elf32_Sym); ++sym_it) {
symbol = symbols_start + sym_it;
if(ELF32_ST_TYPE(symbol->st_info) != STT_FUNC)
continue;
if(strncmp(strtab + symbol->st_name, DL_OPEN_NAME, sizeof DL_OPEN_NAME) && !rt_info->dlopen) {
//printf("Offset of dlopen: 0x%x\n", symbol->st_value);
dlopen = ((char *)ehdr) + symbol->st_value;
} else if(strncmp(strtab + symbol->st_name, DL_SYM_NAME, sizeof DL_SYM_NAME) && !rt_info->dlsym) {
//printf("Offset of dlsym: 0x%x\n", symbol->st_value);
dlsym = ((char *)ehdr) + symbol->st_value;
}
if(dlopen != 0 && dlsym != 0)
return 0;
}
}
}
return -1;
}
void *get_dynstr_section()
{
Elf32_Ehdr *ehdr = libdl_start;
Elf32_Shdr *shdr, *shdrs_start = (Elf32_Shdr *)(((char *)ehdr) + ehdr->e_shoff);
char *strtab = ((char *)ehdr) + ((shdrs_start + ehdr->e_shstrndx))->sh_offset;
int sec_it = 0;
for(sec_it = 0; sec_it < ehdr->e_shnum; ++sec_it) {
// Iterate over all sections to find .dynstr section
shdr = shdrs_start + sec_it;
if(shdr->sh_type == SHT_STRTAB && strncmp(strtab + shdr->sh_name, DYNSTR_NAME, sizeof DYNSTR_NAME))
return ((char *)ehdr) + shdr->sh_offset;
}
return NULL;
}
You do NOT need to mmap the shared library again - the system already did it- but you cannot rely on the section headers. The section headers are only for the linking view of an ELF file and often aren't allocated into a program segment. You will need to look at it from the execution view. The section .dynstr is always loaded into memory. Otherwise dynamic linking wouldn't work. To get at it, go through the program headers to find the PT_DYNAMIC segment. It will have elements DT_SYMTAB and DT_STRTAB that correspond to .dynsym and .dynstr. You may also have to adjust the address values using a base address. It's very common especially with ASLR for shared objects to be mapped at different virtual addresses than they were linked at. You can find this adjustment amount by subtracting the lowest virtual address in a PT_LOAD entry from the lowest mapped segment in the memory map. Or even better use the link map maintained by ld.so. It contains the base address, the path of the shared object, and a pointer to the shared object's dynamic area. Consult for how this is laid out. If you are running Linux, you might be very interested in the function dl_iterate_phdr(). It's great for finding things about the libraries mapped into the current process image. If you want to examine another process you have to roll your own.
why the ELF header is changed during loading of the library
It isn't. Your question is based on false assumption, but since you didn't show any actual code, it's hard to guess what you've done wrong.
Update:
In this code:
*shdrs_start = (Elf32_Shdr *)(((char *)ehdr) + ehdr->e_shoff);
you assume that sections headers are loaded into memory. But sections headers are not required at runtime, and if they end up loaded into memory, it's only by accident.
You need to read them into memory from disk (or mmap them) yourself, using the e_shoff you got from ehdr.

Midnite commander ELF viewer - what do the symbols mean?

I have a small program which when viewed in Midnite Commander looks like this:
/home/adrian/Imperas/mb_boot /startup.MICROBLAZE.elf 486/486 100%
/home/adrian/Imperas/mb_boot/startup.MICROBLAZE.elf: ELF 32-bit MSB executable, version 1 (SYSV), dynamically linked (uses shared libs), not stripped
100000f0 T _actualstart
100012b4 A __bss_start
10001228 d _DYNAMIC
100012b4 A _edata
100012b4 A _end
100012a8 d _GLOBAL_OFFSET_TABLE_
1000010c t _handle_exception
1000010c t _handle_hwexception
1000010c t _interrupt_handler
10000110 T _start
10000128 t _vector_hw_exception
10000120 t _vector_interrupt
10000118 t _vector_sw_exception
The various symbols eg _vector_sw_exception correspond to what I have in the assembly - but what do the A, T, t and so on mean?
From the nm(1) man page:
"A" The symbol's value is absolute, and will not be changed by
further linking.
...
"T"
"t" The symbol is in the text (code) section.
And so on.

How to get right MIPS libc toolchain for embedded device

I've run into a problem (repetitively) with various company's' embedded linux products where GPL source code from them does not match what is actually running on a system. It's "close", but not quite right, especially with respect to the standard C library they use.
Isn't that a violation of the GPL?
Often this mismatch results in a programmer (like me) cross compiling only to have the device reply cryptically "file not found" or something similar when the program is run.
I'm not alone with this kind of problem -- For many people have threads directly and indirectly related to the problem: eg:
Compile parameters for MIPS based codesourcery toolchain?
And I've run into the problem on Sony devices, D-link, and many others. It's very common.
Making a new library is not a good solution, since most systems are ROMFS only, and LD_LIBRARY_PATH is sometimes broken -- so that installing a new library on the device wastes very limited memory and often won't work.
If I knew what the right source code version of the library was, I could go around the manufacturer's carelessness and compile it from the original developer's tree; but how can I find out 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 a DSL modem's libc (see below); but I don't see anything here that could tell me exactly which libc it was...
How can I find the name of the source code, or an identifier from the library's binary so I can create a cross compiler using that library? eg: Can anyone tell me what source code this library came from, and how 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's 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 to put useful information about the subject in one place.
Don't bother reading it unless you want to know I actually did research the question... in gory detail... and how NOT to answer my question.
The proper (theoretical) way to get a libc program running on (for example) a D-link modem would simply be to get the TRUE source code for the product from the manufacturer, and compile against those libraries.... (It's GPL !? right, so the law is on our side, right?)
For example: I just bought a D-Link DSL-520B modem and a 526B modem -- but found out after the fact that the manufacturer "forgot" to supply linux source code for the 520B but does have it for the 526B. I checked all of the DSL-5xxB devices online for source code & toolchains, finding to my delight that ALL of them (including 526B) -- contain the SAME pre-compiled libc.so.0 with MD5sum of 6ed709113ce615e9f170aafa0eac04a6 . So in theory, all supported modems in the DSL-5xxB family seemed to use the same libc library... and I hoped I might be able to use that library.
But after I figured out how to get the DSL modem itself to send me a copy of the installed /lib/libc.so.0 library -- I found to my disgust that they ALL use a library with MD5 sum of b8d492decc8207e724a0822641205078 . In NEITHER of the modems I bought (supported or not) was found the same library as contained in the source code toolchain.
To verify the toolchain from D-link was defective, I didn't compile a program (the toolchain wouldn't run on my PC anyway as it was the wrong binary format) -- but I found the toolchain had some pre-compiled mips binaries in it already; so I simply downloaded one to the modem and chmod +x -- and (surprise) I got the message "file not found." when I tried to run it ... It won't run.
So, I knew the toolchains were no good immediately, but not exactly why.
I decided to get a newer verson of MIPS GCC (binary version) that should have less bugs, more features and which is supported on most PC platforms. This is the way to GO!
See: Kernel.org pre-compiled binaries
I upgraded to gcc 4.9.0 after selecting the older "mips" verson from the above site to get the right FTP page; and set my shells' PATH variable to the /bin directory of the cross compiler once installed.
Then I copied all the header files and libraries from the D-link source code package into the new cross compiler just to verify that it could compile D-link libc binaries. And it did on the first try, compiling "hello world!" with no warnings or errors into a mips 32 big endian binary.
( START EDIT: ) #ChrisStratton points out in the comments (after this post) that my test of the toolchain is inadequate, and that using a newer GCC with an older library -- even though it links properly -- is flawed as a test. I wish there was a way to give him points for his comments -- I've become convinced that he's right; although that makes what D-link did even a worse problem -- for there's no way to know from the binaries on the modem which GCC they actually used. The GCC used for the kernel isn't necessarily the same used in user space.
In order to test the new compiler's compatibility with the modems and also make tools so I could 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 ran just fine... and the code is attached to show how it can be done.
The first listing is an assembly language program to bypass linking the standard C libraries on MIPS; and the second listing is a program meant to create an octal number dump of a binary file/stream using only the linux kernel. eg: It enables copying/pasting or scripting of binary data over telnet, netcat, etc... via ash/bash or busybox :) like a poor man's uucp.
// 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 mips' octdump was saved (chmod +x) as /var/octdump on the modem, it ran without errors.
(use your imagination about how I got it on there... Dlink's TFTP, & friends are broken.)
I was able to use octdump to copy all the dynamic libraries off the DSL modem and examine them, using an automated script to avoid copy/pasting by hand.
#!/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 might cross compile using these libraries since (at least in theory) -- GCC could link against them; and my problem might be solved.
I made very sure to erase all the incompatible .so libraries from gcc-4.9.0/mips-linux/mips-linux/lib, but kept the generic crt..o files; then I copied the modem's libraries into the cross compiler directory.
But even though the kernel version of the source code, and the kernel version of the modem matched -- GCC found undefined symbols in the crt files.... So, either the generic crt files or the modem libraries themselves are somehow defective... and I don't know why. Without knowing how to get the full library version of the ? ucLibc ? library, I'm not sure how I can get the CORRECT source code to recompile the libraries and the crt's from scratch.

Resources