[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

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: