A friend recently encountered a tricky problem. He hoped to load the Shared Library (so) to the specified memory address, probably to speed up application startup through prelink. He asked me if I could do anything. I know that it works in windows. For example, you can set the/base value in vc6, so I believe it is feasible in Linux. You can set the compilation options for VC. I guess GCC should also be available. GCC itself is only a shell, and the link work is completed by LD. Of course, you should read the LD command line option document. Soon we found that LD has a-image-base option, which allows you to set the loading address of the dynamic library. This parameter is passed to LD through xlinker, but ld cannot recognize this option:
Gcc-g-shared test. C-xlinker -- image-base-xlinker 0x00c00000-O libtest. So
/Usr/bin/ld: Unrecognized option '-- image-base'
/Usr/bin/ld: Use the -- help option for usage information
Collect2: LD returned 1 exit statu
STake a closer look at the manual. In the past, this option only applies to PE files. PE files are dedicated in windows and cannot be used in Linux. It seems that you have to find another method. I know that LD script can control the behavior of LD, So I studied the writing of LD script. According to the instructions in the manual, I wrote a simple lD script:
| Sections {. = 0x00c00000;. Text: {* (. Text)}. Data: {* (. Data)}. BSS: {* (. BSS )}} |
Compile as follows:
Gcc-shared-g-xlinker -- script-xlinker lD. s test. C-o libtest. So
Gcc-G main. C-L./-ltest-O test.exeUse LDD to check whether the load address is correct.
[Root @ localhost lDs] # LDD test.exe
Linux-gate.so.1 => (0x00aff000)
Libtest. So =>./libtest. So (0x00c00000)
Libc. so.6 =>/lib/libc. so.6 (0x007fa000)
/Lib/ld-linux.so.2 (0x007dd000)
However, crash:
[Root @ localhost lDs] #./test.exe
Segmentation faultDebugging and running can be found:
(GDB) r
Starting program:/work/test/lDs/test.exe
Reading symbols from shared object read from target memory... done.
Loaded system susupplied DSO at 0x452000
Program received signal SIGSEGV, segmentation fault.
0x007e7a10 in _ dl_relocate_object () from/lib/ld-linux.so.2
(GDB) BT
#0 0x007e7a10 in _ dl_relocate_object () from/lib/ld-linux.so.2
#1 0x007e0833 in dl_main () from/lib/ld-linux.so.2
#2 0x007f056b in _ dl_sysdep_start () from/lib/ld-linux.so.2
#3 0x007df48f in _ dl_start () from/lib/ld-linux.so.2
#4 0x007dd847 in _ start () from/lib/ld-linux.so.2The conjecture may be that lD. S is not fully written, resulting in incorrect information. Therefore, use LD-verbose to export a default LD script. As expected, the default LD script is very lengthy. The following is the first section:
| /* Script for-Z combreloc: Combine and sort reloc seloc */output_format ("elf32-i386", "elf32-i386", "elf32-i386") output_arch (i386) entry (_ start) search_dir ("/usr/i386-redhat-linux/lib"); search_dir ("/usr/local/lib"); search_dir ("/lib "); search_dir ("/usr/lib"); sections {/* read-only sections, merged into text segment: */provide (_ executable_start = 0x08048000 );. = 0x08048000 + sizeof_headers ;. interp :{*(. interp )}. hash :{*(. hash )}. dynsym :{*(. dynsym )}. dynstr :{*(. dynstr )}. GNU. version :{*(. GNU. version )}. GNU. version_d :{*(. GNU. version_d )}. GNU. version_r :{*(. GNU. version_r )} |
According to the LD script syntax, I changed it to (the red part is the new row ):
| /* Script for-Z combreloc: Combine and sort reloc seloc */output_format ("elf32-i386", "elf32-i386", "elf32-i386") output_arch (i386) entry (_ start) search_dir ("/usr/i386-redhat-linux/lib"); search_dir ("/usr/local/lib"); search_dir ("/lib "); search_dir ("/usr/lib"); sections {/* read-only sections, merged into text segment: */provide (_ executable_start = 0x08048000 );. = 0x08048000 + sizeof_headers ;. = 0x00c00000 ;. interp :{*(. interp )}. hash :{*(. hash )}. dynsym :{*(. dynsym )}. dynstr :{*(. dynstr )}. GNU. version :{*(. GNU. version )}. GNU. version_d :{*(. GNU. version_d )}. GNU. version_r :{*(. GNU. version_r )} |
Use this LD script to test again. Everything works. It is also normal to verify the situation of multiple shared libraries. The following is the test data: Test. c
| Int test (INTN) {returnn ;} |
Test1.c
| Inttest1 (INTN) {returnn ;} |
Main. c
| Externinttest (INTN); externinttest1 (INTN); # include <stdio. h> intmain (intargc, char * argv []) {printf ("Hello: % d/N", test (100), test1 (200 )); getchar (); Return 0 ;} |
Makefile
| ALL: gcc-shared-g-xlinker -- script-xlinker lD. s test. c-o libtest. so gcc-shared-g-xlinker -- script-xlinker ld1.s test1.c-O libtest1.so gcc-G main. c-l. /-ltest-ltest1-O test.exe clean: Rm-f *. so *. EXE |
The load address of libtest. So is 0x00c00000libtest1. So. The load address is 0x00d00000 LDD. The result is as follows:
| Linux-gate.so.1 => (0x00aa3000) libtest. so =>. /libtest. so (0x00c00000) libtest1.so =>. /libtest1.so (0x00d00000) libc. so.6 =>/lib/libc. so.6 (0x007fa000)/lib/ld-linux.so.2 (0x007dd000) |
The content of maps is:
| 007dd000-007f6000 R-XP 00000000 0:01 521466/lib/ld-2.4.so007f6000-007f7000 R-XP 00018000 0:01 521466/lib/ld-2.4.so007f7000-007f8000 rwxp 00019000 0:01 521466/lib/ld-2.4.so007fa000-00926000 R-XP 00000000 0:01 523579/lib/libc-2.4.so00926000-00929000 R -XP 0012b000 0:01 523579/lib/libc-2.4.so00929000-0092a000 rwxp 0012e000 0:01 523579/lib/libc-2.4.so0092a000-0092d000 rwxp 0092a000 00:00 0 00c00000-00c01000 R-XP 00001000 0:03 16370/work/test/ldsex/libtest. so00c01000-00c02000 rwxp 00001000 16370/work/test/ldsex/libtest. so00cf1000-00cf2000 R-XP 00cf1000 00:00 0 [vdso] 1200r-XP 00001000 0:03 16373/work/test/ldsex/libtest1.so00d01000-00d02000 rwxp 00001000 0:03 16373/work/test/ldsex/others- 08049000 R-XP 00000000 0:03 16374/work/test/ldsex/test.exe 08049000-0804a000 RW-P 00000000 0:03 16374/work/test/ldsex/test.exe b7fdf000-b7fe0000 RW-P b7fdf000 00:00 0 b7fed000-b7ff0000 RW- P b7fed000 00:00 0 bf8db000-bf8f0000 RW-P bf8db000 00:00 0 [Stack] |
The above test results show that this method is feasible.