Re: porting to uClibc-based 686 Linux

Am posting this follow-up to two mailing lists, because I've inquired about it on both. Previous messages are at: * http://www.haskell.org/pipermail/glasgow-haskell-users/2013-April/023912.htm... * http://lists.alpinelinux.org/alpine-devel/1699.html I have seemed to successfully cross-compile a stage2 ghc for my target system, an i686 Linux based on uClibc. One issue I don't think I've mentioned before is that the target system uses a kernel with grsecurity and PaX, and that involves patching the toolchain as well. However my cross-compiling toolchain doesn't have any such tweaks applied. This will be relevant below. Another potential issue is that my host system, a different i686 Linux based on glibc, is running inside a chroot on my target system. I don't think this is in fact responsible for any problems, but I thought I should mention it. So I last wrote on the glasgow-haskell mailing list: On Wed, Apr 03, 2013 at 10:55:14AM -0400, Dubiousjim wrote:
But there's still something funny with the binaries generated by the compiler. That means I can't yet use this ghc to directly recompile ghc on my target system.
$ cat ~/hello.hs main = putStrLn "Hello World!\n" $ rm -f hello $ inplace/bin/ghc-stage2 -B./inplace/lib ~/hello.hs -o hello [1 of 1] Compiling Main ( /home/jim/hello.hs, /home/jim/hello.o ) [flags changed] Linking hello ... $ ./hello Can't modify application's text section; use the GCC option -fPIE for position-independent executables.
Seems like I'm close, but not quite there yet.
Supplying the flag -fPIE to ghc when building hello says:
ghc-stage2: unrecognised flags: -fPIE
The flag -fPIC on the other hand is accepted, but then the generated binary hello still fails with the same error.
Krzysztof replied to me offline (thanks Krzysztof!), but I still haven't managed to get this to work. I started thinking the difficulty came from the grsecurity or PaX features of my target system. Maybe the toolchain on the target system had been configured in a way to build binaries that would work ok on that system, but ghc wasn't yet so configured, and that's why the binaries compiled by ghc don't work. I wrote to my target system's mailing list (alpine-devel@lists.alpinelinux.org) expressing this fear. There was also some evidence against this hypothesis. (Test binaries I built using the cross-compiling toolchain, which hadn't been tweaked in the way the toolchain on the target system had, did build binaries that executed fine on the target; but perhaps this was just because the test programs were too simple.) But since I didn't know what was going on, this seemed worth exploring. However, I'm pretty confident I've now ruled this explanation out. Even if I build and boot from a vanilla kernel, binaries generated by the ghc-stage2 in question still fail with the error message I reported. So then I started trying to track down the error message in any sources or binaries on my system. Couldn't find it kernel or ghc sources. I did find it though in the source code for the uClibc library. It's from lines 614-681 of the file uClibc-0.9.33.2/ldso/ldso/ldso.c: ----------------------------- start ----------------------------------- /* At this point we are now free to examine the user application, * and figure out which libraries are supposed to be called. Until * we have this list, we will not be completely ready for dynamic * linking. */ /* Find the runtime load address of the main executable. This may be * different from what the ELF header says for ET_DYN/PIE executables. */ { unsigned int idx; ElfW(Phdr) *phdr = (ElfW(Phdr) *) auxvt[AT_PHDR].a_un.a_val; for (idx = 0; idx < auxvt[AT_PHNUM].a_un.a_val; idx++, phdr++) if (phdr->p_type == PT_PHDR) { DL_INIT_LOADADDR_PROG(app_tpnt->loadaddr, auxvt[AT_PHDR].a_un.a_val - phdr->p_vaddr); break; } if (DL_LOADADDR_BASE(app_tpnt->loadaddr)) _dl_debug_early("Position Independent Executable: " "app_tpnt->loadaddr=%x\n", DL_LOADADDR_BASE(app_tpnt->loadaddr)); } /* * This is used by gdb to locate the chain of shared libraries that are * currently loaded. */ debug_addr = _dl_zalloc(sizeof(struct r_debug)); ppnt = (ElfW(Phdr) *) auxvt[AT_PHDR].a_un.a_val; for (i = 0; i < auxvt[AT_PHNUM].a_un.a_val; i++, ppnt++) { if (ppnt->p_type == PT_GNU_RELRO) { relro_addr = ppnt->p_vaddr; relro_size = ppnt->p_memsz; } if (!app_mapaddr && (ppnt->p_type == PT_LOAD)) { app_mapaddr = DL_RELOC_ADDR (app_tpnt->loadaddr, ppnt->p_vaddr); } if (ppnt->p_type == PT_DYNAMIC) { dpnt = (ElfW(Dyn) *) DL_RELOC_ADDR(app_tpnt->loadaddr, ppnt->p_vaddr); _dl_parse_dynamic_info(dpnt, app_tpnt->dynamic_info, debug_addr, app_tpnt->loadaddr); #ifndef __FORCE_SHAREABLE_TEXT_SEGMENTS__ /* Ugly, ugly. We need to call mprotect to change the * protection of the text pages so that we can do the * dynamic linking. We can set the protection back * again once we are done. */ _dl_debug_early("calling mprotect on the application program\n"); /* Now cover the application program. */ if (app_tpnt->dynamic_info[DT_TEXTREL]) { ElfW(Phdr) *ppnt_outer = ppnt; ppnt = (ElfW(Phdr) *) auxvt[AT_PHDR].a_un.a_val; for (i = 0; i < auxvt[AT_PHNUM].a_un.a_val; i++, ppnt++) { if (ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W)) _dl_mprotect((void *) (DL_RELOC_ADDR(app_tpnt->loadaddr, ppnt->p_vaddr) & PAGE_ALIGN), (DL_RELOC_ADDR(app_tpnt->loadaddr, ppnt->p_vaddr) & ADDR_ALIGN) + (unsigned long) ppnt->p_filesz, PROT_READ | PROT_WRITE | PROT_EXEC); } ppnt = ppnt_outer; } #else if (app_tpnt->dynamic_info[DT_TEXTREL]) { _dl_dprintf(_dl_debug_file, "Can't modify application's text section; use the GCC option -fPIE for position-independent executables.\n"); _dl_exit(1); } #endif ----------------------------- end ----------------------------------- and indeed, the ghc-stage2 I built does seem to be generating position-dependent code, EVEN WHEN I TELL IT -fPIC. Whereas the native ghc on my host system doesn't do so, even when -fPIC is omitted. Witness: host$ which ghc /usr/bin/ghc host$ cat hello.hs main = putStrLn "Hello World!\n" host$ /usr/bin/ghc -o hello-host hello.hs [1 of 1] Compiling Main ( hello.hs, hello.o ) Linking hello-host ... There we've compiled hello-host using the host's native ghc. Now we switch over to the target system (sharing the same filesystem, and cding to the same directory): target$ rm -f hello.o hello.hi target$ inplace/bin/ghc-stage2 -o hello-cross hello.hs [1 of 1] Compiling Main ( hello.hs, hello.o ) Linking hello-cross ... target$ ./hello-cross Can't modify application's text section; use the GCC option -fPIE for position-independent executables. target$ rm -f hello.o hello.hi hello-cross target$ inplace/bin/ghc-stage2 -fPIC -o hello-cross hello.hs [1 of 1] Compiling Main ( hello.hs, hello.o ) Linking hello-cross ... target$ ./hello-cross Can't modify application's text section; use the GCC option -fPIE for position-independent executables. target$ readelf -d hello-host | fgrep TEXTREL target$ readelf -d hello-cross | fgrep TEXTREL 0x00000016 (TEXTREL) 0x0 So something has gone wrong with the way I cross-compiled or have configured this ghc-stage2. It won't build position-independent code whereas the native ghc running on my host system will. So I come back to the ghc folks for advice. I hope some readers might make it this far and have suggestions or advice about things I might try. -- dubiousjim@gmail.com

On Fri, Apr 05, 2013 at 11:12:38PM -0400, Dubiousjim wrote:
target$ inplace/bin/ghc-stage2 -o hello-cross hello.hs [1 of 1] Compiling Main ( hello.hs, hello.o ) Linking hello-cross ... target$ ./hello-cross Can't modify application's text section; use the GCC option -fPIE for position-independent executables.
You can pass -fPIE to gcc by using the -optc-fPIE flag. Thanks Ian
participants (2)
-
Dubiousjim
-
Ian Lynagh