Re: Problems executing /lib/ld-linux.so.2
Juan Cespedes wrote:
> Hi.
>
> I have been trying to compile a new glibc many, many times,
> wasting a lot of time :), and it always failed in a point where the
> dynamic linker (ld-linux.so.2) was executed with one program as the
> argument. IMHO, that is one of the best things the new libc has, but
> it never worked for me in sparc. Example:
>
> [i386] $ /lib/ld-linux.so.2 /bin/ls -al
> total 2
> drwxr-xr-x 2 root root 1024 Nov 17 11:43 .
> drwxr-xr-x 8 root root 1024 Nov 17 11:43 ..
>
> [sparc] $ /lib/ld-linux.so.2 /bin/ls -al
> [it hangs]
>
> Well, it sometimes hangs, but sometimes dies with SIGSEGV,
> sometimes with SIGBUS, sometimes with SIGILL...
ld-linux is to big to fit in the 64kb reserved for loader in the memory when
loading executables. There is a patch against 2.0.30 to fix this bug (maybe
already fixed in newer kernels, don't know).
I attached it to this mail.
Regards.
--
Eric Delaunay | "La guerre justifie l'existence des militaires.
delaunay@lix.polytechnique.fr | En les supprimant." Henri Jeanson (1900-1970)
diff -ruNp sparclinux-stable/fs/binfmt_elf.c sls-rth/fs/binfmt_elf.c
--- sparclinux-stable/fs/binfmt_elf.c Tue May 27 22:47:19 1997
+++ sls-rth/fs/binfmt_elf.c Sun Jun 15 07:38:35 1997
@@ -119,15 +119,15 @@ unsigned long * create_elf_tables(char *
/*
* Force 16 byte alignment here for generality.
*/
- sp = (unsigned long *) (~15UL & (unsigned long) p);
-#ifdef __sparc__
+ sp = (unsigned long *) (-sizeof(long) & (unsigned long)p);
csp = sp;
csp -= exec ? DLINFO_ITEMS*2 : 2;
csp -= envc+1;
csp -= argc+1;
- if (!(((unsigned long) csp) & 4))
- sp--;
-#endif
+ csp -= 1; /* argc */
+ if ((unsigned long) csp & 15UL)
+ sp -= (16 - ((unsigned long) csp & 15UL)) / sizeof(long);
+
sp -= exec ? DLINFO_ITEMS*2 : 2;
dlinfo = sp;
sp -= envc+1;
@@ -385,13 +385,13 @@ do_load_elf_binary(struct linux_binprm *
struct file * file;
struct exec interp_ex;
struct inode *interpreter_inode;
- unsigned long load_addr;
+ unsigned long load_addr, load_bias;
int load_addr_set = 0;
unsigned int interpreter_type = INTERPRETER_NONE;
unsigned char ibcs2_interpreter;
int i;
int old_fs;
- int error;
+ unsigned long error;
struct elf_phdr * elf_ppnt, *elf_phdata;
int elf_exec_fileno;
unsigned long elf_bss, k, elf_brk;
@@ -405,7 +405,7 @@ do_load_elf_binary(struct linux_binprm *
ibcs2_interpreter = 0;
status = 0;
- load_addr = 0;
+ load_addr = load_bias = 0;
elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */
if (elf_ex.e_ident[0] != 0x7f ||
@@ -582,6 +582,19 @@ do_load_elf_binary(struct linux_binprm *
bprm->p = setup_arg_pages(bprm->p, bprm);
current->mm->start_stack = bprm->p;
+ /* Try and get dynamic programs out of the way of the default mmap
+ base, as well as whatever program they might try to "exec".
+ This is because the brk will follow the loader, and is not
+ movable. */
+
+ if (elf_ex.e_type == ET_DYN) {
+#ifdef __sparc__
+ load_bias = TASK_UNMAPPED_BASE - 0x10000000;
+#else
+ load_bias = 2 * TASK_SIZE / 3;
+#endif
+ }
+
/* Now we do a little grungy work by mmaping the ELF image into
the correct location in memory. At this point, we assume that
the image should be loaded at fixed address, not at a variable
@@ -591,29 +604,41 @@ do_load_elf_binary(struct linux_binprm *
set_fs(get_ds());
for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
if (elf_ppnt->p_type == PT_LOAD) {
- int elf_prot = 0;
+ int elf_flags, elf_prot = 0;
+ unsigned long vaddr = 0;
+
if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
+ elf_flags = MAP_PRIVATE|MAP_DENYWRITE|MAP_EXECUTABLE;
+
+ if (elf_ex.e_type == ET_EXEC || load_addr_set) {
+ vaddr = elf_ppnt->p_vaddr;
+ elf_flags |= MAP_FIXED;
+ }
+
error = do_mmap(file,
- ELF_PAGESTART(elf_ppnt->p_vaddr),
+ ELF_PAGESTART(load_bias + vaddr),
(elf_ppnt->p_filesz +
ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
- elf_prot,
- (MAP_FIXED | MAP_PRIVATE |
- MAP_DENYWRITE | MAP_EXECUTABLE),
+ elf_prot, elf_flags,
(elf_ppnt->p_offset -
ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
#ifdef LOW_ELF_STACK
- if (ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack)
- elf_stack = ELF_PAGESTART(elf_ppnt->p_vaddr);
+ if (error < elf_stack)
+ elf_stack = error-1;
#endif
if (!load_addr_set) {
- load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
- load_addr_set = 1;
+ load_addr_set = 1;
+ load_addr = (elf_ppnt->p_vaddr -
+ elf_ppnt->p_offset);
+ if (elf_ex.e_type == ET_DYN) {
+ load_bias = error;
+ load_addr += error;
+ }
}
k = elf_ppnt->p_vaddr;
if (k < start_code) start_code = k;
@@ -632,6 +657,13 @@ do_load_elf_binary(struct linux_binprm *
}
set_fs(old_fs);
+ elf_entry += load_bias;
+ elf_bss += load_bias;
+ elf_brk += load_bias;
+ start_code += load_bias;
+ end_code += load_bias;
+ end_data += load_bias;
+
if (elf_interpreter) {
if (interpreter_type & 1)
elf_entry = load_aout_interp(&interp_ex,
@@ -673,7 +705,7 @@ do_load_elf_binary(struct linux_binprm *
bprm->inode->i_count++;
#endif
#ifdef LOW_ELF_STACK
- current->start_stack = bprm->p = elf_stack - 4;
+ current->start_stack = bprm->p = elf_stack;
#endif
current->suid = current->euid = current->fsuid = bprm->e_uid;
current->sgid = current->egid = current->fsgid = bprm->e_gid;
Reply to: