Bug 16794 – dmd not working on Ubuntu 16.10 because of default PIE linking
Status
RESOLVED
Resolution
FIXED
Severity
critical
Priority
P1
Component
phobos
Product
D
Version
D2
Platform
x86_64
OS
Linux
Creation time
2016-11-25T23:22:00Z
Last change time
2017-01-16T23:25:54Z
Assigned to
nobody
Creator
hsteoh
Comments
Comment #0 by hsteoh — 2016-11-25T23:22:13Z
The latest versions of Debian / Ubuntu ship with gcc-6.2 configured with PIE by default. Because of this, existing .deb packages of the dmd toolchain will not be able to link D executables due to incompatibility between non-PIC code in libphobos2.a and PIC code generated by default when gcc is invoked by dmd.
Recommend to change the official build scripts for .deb packages so that PIC=1 is specified by default for druntime/phobos builds, so that libphobos2.a is compiled with -fPIC. Note that this will also require that the default dmd.conf specify -fPIC in the default compiler flags, otherwise users may still run into PIC/non-PIC incompatibility problems.
See also:
https://issues.dlang.org/show_bug.cgi?id=13149https://issues.dlang.org/show_bug.cgi?id=15054https://wiki.debian.org/Hardening
Comment #1 by hsteoh — 2016-11-25T23:25:34Z
Alternatively, DMD needs to invoke gcc with -no-pie when linking D executables.
However, I rather we don't go this route, because this would preclude ASLR (Address Space Layout Randomization) on all generated D executables. In the long run I think this is a bad strategic move.
Comment #2 by issues.dlang — 2016-11-30T02:42:08Z
I've tried to bootstrap dmd on (k)ubuntu 16.10 in two different ways:
1. Compiling and installing dmd 2.067.1 and then trying to build 2.071.0 with it.
2. Compiling 2.071.0 with the ldc currently in the ubunto repos which shows
LDC - the LLVM D compiler (0.17.1):
based on DMD v2.068.2 and LLVM 3.8.0
as its version.
In both cases, to get dmd building, I've had to add -Wno-narrowing to dmd's src/posix.mak like so
BACK_FLAGS := -I$(ROOT) -I$(TK) -I$(C) -I. -DDMDV2=1 -Wno-narrowing
or dmd failed to compile due to errors related to narrowing conversions. When I built druntime and Phobos, I compiled them with PIC=1. I was able to build dmd 2.067.1 and its corresponding druntime and phobos in this manner (after which I added -fPIC to its dmd.conf). However, whether I built dmd 2.070.0 with dmd 2.067.1 or with ldmd2 -fPIC, I ran into the same build error. dmd 2.070.0 built fine, but its druntime failed with
Internal error: backend/elfobj.c 1027
posix.mak:184: recipe for target 'generated/linux/release/64/libdruntime.a' failed
which looks like is what is being hit in bug #15935, though there, it's reporting it for dub rather than druntime.
Comment #3 by code — 2016-11-30T22:33:49Z
See https://issues.dlang.org/show_bug.cgi?id=5278#c32 for a solution, compiling with -fPIC -defaultlib=libphobos2.so.
I'm not certain whether we should build a static library (intended for static linking) with position independent code?
Does Ubuntu have static libraries, and if so what's their guideline?
Comment #4 by hsteoh — 2016-11-30T23:14:39Z
@Martin: that forces you to link with Phobos dynamically. It doesn't work if you want to statically-link Phobos.
Comment #5 by issues.dlang — 2016-12-01T00:00:11Z
Personally, I actively avoid using the shared version of Phobos, because it makes it very annoying to deal with multiple versions of it, which comes up often when you're actually working on Phobos rather than just installing dmd from the .zip or .deb or whatever. It's also just way nicer to be able to build a binary and not have to worry about rebuilding it because of changes to other stuff on your system. So, regardless of what happens to the actual .deb file, I definitely think that it should be _possible_ to compile phobos as a static library and use it with -fPIC, and right now, as far as I can tell, it isn't - or at least, what you get doesn't work correctly, since the resulting dmd can't build libdruntime.a.
Comment #6 by hsteoh — 2016-12-01T00:29:41Z
To be frank, versioning problems with shared libraries are the fault of the distributors (i.e., us). The current way shared libraries work, the only sane setup is to make the shared library name (or more specifically, the version part of it) *unique* across all potentially-incompatible builds, even if they are ultimately built from the same version of the compiler toolchain. And when linking, executables should link to the specific version of the library that they are compiled with, not with a generic name like libphobos.so that will pick up whatever version you currently have installed, because that WILL break as soon as you upgrade the library. (This is especially bad with our current state of affairs where basically every compiler release is ABI-incompatible with the previous release.)
Currently it seems libphobos.so is versioned by DMD release, which apparently makes sense but actually is not good enough. The version must be bumped for every ABI-incompatible change, not just when the API changes. This includes compiler flags used when building the shared library that may introduce ABI-breakages.
But this approach is also troublesome because it means the .deb's must be built in a way that multiple versions of libphobos.so must be simultaneously installable, otherwise after upgrading to the new release the older libphobos.so is gone and all your old executables won't run anymore. Debian does provide the mechanisms for doing this, but it's pretty involved, and I'm not sure if we have the manpower to babysit a potentially large set of libphobos packages that have to be simultaneously maintained for a good amount of time in order not to break old executables.
In comparisons, static linking looks pretty attractive to me. Especially at this stage in D's development.
Comment #7 by hsteoh — 2016-12-01T00:46:50Z
As for building libphobos.a with -fPIC, it's definitely possible, as I described. At least, I managed to get it to work on my system. I'm not sure what is causing problems on your system that makes this impossible.
To recap, what I did to make it work is:
(1) Bootstrap dmd from an older non-PIE dmd installation:
a) create a wrapper script for gcc/g++ (say, g++wrapper) that invokes it with -no-pie.
b) run make in the dmd subdir with HOST_CXX set to this wrapper, and HOST_DMD set to your bootstrapping compiler. Make sure the bootstrapping compiler's dmd.conf (preferably dedicated for bootstrapping) that has the right paths to its corresponding version of druntime/phobos (which, presumably, are from a non-PIE release).
c) if you're having trouble bootstrapping dmd in spite of this, you may want to check if gcc-specific flags like -Wnarrowing are being passed to gcc when compiling dmd modules. If not, you may need to add a hack to g++wrapper that echoes "g++" when the command-line contains "-version". This is a hack to workaround posix.mak bogonity that tries to parse the output of `cc -version` for identifying signs of gcc, but fails horribly with certain versions of Debian's gcc distribution.
(2) (Re)build druntime/phobos with the new compiler, with PIC=1 passed to the makefile to force libphobos.a to be built with -fPIC.
(3) Edit dmd.conf (of the bootstrapped compiler) and add -fPIC to the default flags.
(4) (optionally) install dmd/libphobos in your system directories.
The new compiler should now be able to successfully compile and link PIE executables that are statically linked to libphobos.a. Note that libphobos.a built this way will be PIC, and may not be linkable to non-PIE executables anymore.
Comment #8 by hsteoh — 2016-12-01T00:50:22Z
P.S. Note that you have to rebuild *both* druntime and phobos (in that order) with PIC=1, otherwise it may not link successfully. And also, you might want to run `make clean` in both druntime and phobos to make sure stale libraries aren't still lying around, before building with PIC=1. Sometimes the makefile just picks up an older non-PIE object file instead and the link will fail.
Comment #9 by issues.dlang — 2016-12-01T01:50:56Z
@hsteoh Well, as I explained before, when I used either my bootstrapped 2.067.1 or ldc to compile the D toolchain, building druntime failed, with the compiler hitting the backend error in bug# 15935. Now, I bootstrapped it differently than you did, and maybe that's the difference. I don't know. But when I bootstrapped it, I used PIC=1 for druntime and Phobos and dmd.conf had -fPIC in it (though the failure was then with the newly built dmd that had been built with either dmd 2.067.1 or ldc, so dmd.conf wouldn't have mattered for the druntime build).
Comment #10 by code — 2016-12-04T20:39:03Z
Let me clarify a few points.
- We're not going to ship PIC for static archives on all platforms. The performance penalty is too big for that.
At the moment we only have a single linux build (https://github.com/dlang/installer/blob/8b3c7efe1e049f73ec5fc526a849904bf80b434d/create_dmd_release/build_all.d#L33), so custom static PIC libraries for Ubuntu require quite some changes to the build scripts.
- Static linking partly defeats the purpose of PIE and ASLR. I'm still missing some reference on how the Ubuntu team deals with static libraries.
Using -fno-pie might be the better choice for now.
Comment #11 by issues.dlang — 2016-12-11T03:05:01Z
Well, there are multiple issues here. The primary one (and really what the focus of this bug report is given title) is that we need a solution that works for the package that we provide for debian-based systems. Ideally, it should support both static and shared libraries like we do on other linux systems, which - if I understand correctly - means that everything needs to be built with PIC in order to be able to link with the system libraries. Whether PIC is actually useful for a static libary is a separate issue. Now, if we can't get static libraries working at the moment, then at least getting shared libraries working would be in a _far_ better place than we are now, but really, they both should work. If it's possible to do it all without PIC and PIE and have it work on debian-based systems, then that's fine too, since the main problem is being able to use D at all (though I think that we do need PIE/PIC in order to work with the system libraries, since they're built with PIC).
The other issue is just PIC in general. You should be able to build with PIC/PIE or not on linux systems with D just like you would with C/C++. We clearly have at least partial support for that, and we may have full support for it. It's not entirely clear to me what the situation is.
If I build the druntime unittest build with 2.071.0 like I did before, then I get an ICE. The same for 2.071.1. However, 2.072.x does not seem to have that problem. Rather, it results in the "'__dmd_personality_v0' can not be used when making a shared object; recompile with -fPIC" error, even though I compiled with PIC=1. However, the _phobos unit tests compile and run with PIC=1 fine. So, I think that the problem is that druntime's unittest build doesn't fully support PIC.
However, if I build master, I then get the ICE again - but with building the normal druntime build and not just the unittest build. So, it looks like we have problems with building PIE/PIC, depending on which version of the compiler you're dealing with.
That being the case, I don't know how well dmd will work with PIC/PIE if we're provide debian package with such a build. But it looks like it's quite possible to bootstrap it and build 2.072.1 (as long as you don't care about running druntime's unit tests anyway). We need to fix that ICE for master though (so, bug #15935).
Comment #12 by issues.dlang — 2016-12-11T03:15:32Z
Okay. I take back what I just said about master. Either I had my machine in a funky state (I kept jumping between branches and might have screwed something up), or updating fixed it, but the ICE is gone just like it is in 2.072.x. The druntime unittest build still fails, but the non-unittest build works, and phobos' unittest build works.
Comment #13 by code — 2016-12-23T17:56:57Z
Shared libraries are working, people were asking for PIE support with static phobos libraries.
I'm running benchmarks atm., but even if those were OK for -fPIC on amd64, we still have a few problems.
Phobos built with -fPIC can't be used without -fPIC (because some modules, e.g. SHA1, check for version (D_PIC)) atm.
OTOH distributing phobos with and without PIC might bloat the binary package, and runs into the annoying limitations of dmd's CLI to select the right one.
Using -fno-pie by default remains the easiest path forward.
Comment #14 by code — 2016-12-23T18:55:15Z
Benchmarks are OK, tested druntime/benchmarks and Higgs.
The missing PIC support of the asm SHA code is the only slowdown. It's also the main blocker for shipping a PIC compiled static phobos on all linux amd64 platforms.
Hopefully not to difficult to fix, also see issue 9378.
Comment #15 by github-bugzilla — 2016-12-25T01:04:55Z