Category Archives: General

Paraphernalia and chaos.

Garden work

Another post which is not about software! I’ve recently, finally, finished reworking my garden, and here’s a brief writeup of what happened. It includes some ideas for low-embodied energy and ecologically friendly garden design.

The original garden

This house is on a hill. The original garden was a set of three concrete slabbed terraces going down the hill, with some wooden decking on the top terrace. There was a block paved path ramping down the garden, separating the decking from a sloping grass lawn. There were very few plants which weren’t grass or a few pots.

Problems with this included:

  • Decking was rotten
  • Lower terrace served no purpose and was devoid of life
  • There was very little biodiversity in the garden, and no space to grow anything
  • Steps in the path had been installed with uneven heights and that was surprisingly annoying

The plan

  • Get rid of the decking because it’s rotten
  • Remove the terraces because they’re just concrete, and replace them with more soil and planting area
  • Make the subdivisions of the garden less rectilinear so it feels a bit less brutal
  • Lower some areas of the terraces a bit to get a bit more privacy (the garden is overlooked)
  • Severely reduce the grass lawn area, because it requires frequent mowing and is not very ecologically diverse
  • Rebuild the path to make it curvy and add some planting area in a sunny spot by it
  • Keep the garden adaptable and don’t make anything too permanent (by cementing it in place) — I, or others, may want to rearrange things in future

Executing the plan

I started on this in 2019. Progress was slow at first, because a large part of the plan involved digging out the terraces, and there was some question about whether this would undermine the foundations of the house. That could cause the house to fall down. That would be bad.

I talked to a structural engineer, and he specified a retaining wall system I could install, which would retain the house wall and foundations, act as a raised bed, and is made out of wood so would have low embodied carbon compared to a (more standard) masonry wall (which is about 40kgCO2e/m2, see table 11 here). There was various other research and considerations about adjoining property, safety, drainage, appearance of the materials as they age, and suitability for DIY which fed into this decision. I can go into the details if anyone’s interested (get in touch if so).

What followed was about 10 months of intermittent work on it, removing the old terraces, digging a pond and sowing some wildflowers, installing the new retaining wall, fixing drainage through the clay, bringing in soil, laying a clover lawn, and rebuilding the path.

The result

I’m pretty pleased with the result. There are a few decisions in particular which I’m quite pleased worked out, as they’re not a common approach in the UK and were a bit of a gamble:

  • Clover patio. Rather than a paved patio area (as is common here), I planted clover seed on a thin bed of soil with a weed control membrane beneath. This has a significantly lower embodied carbon than paving (around 100-200kgCO2e/tonne less, if imported natural stone was used, which is the standard in the UK at the moment), and drains better, so it doesn’t contribute to flash flooding runoff. With rain becoming less frequent but more intense in the UK, runoff is going to become more of a problem. My full analysis of the options is here. I chose clover for the planting because it doesn’t require mowing, and should stay short enough to sit on. As per table 1 of this paper, I might adjust the planting in future to include other non-grass species.
  • Wooden retaining wall. I used Woodblocx, and it worked out great. It didn’t require any cementatious materials (which have high embodied carbon), just a compacted type 2 sub-base and their wooden blocks. It’s repairable, and recyclable at end of life (in about 25 years).
  • Wood chip path. This was easy to install (wood chips over a weed control membrane), doesn’t contribute to flash flooding runoff like paved paths do, and is a good environment for various insects which like damp and dark places. It will need topping up with more wood chips every few years, but no other maintenance. The path edging is made from some of the old decking planks from the original garden (the ones which weren’t rotten).
  • Water butt stands. These are all made from bits of old decking or Woodblocx offcuts, and make the water butts easier to use by bringing the tap to a more reachable level. I also made a workbench out of old decking planks.

Subjectively, now the garden’s been basically finished for a year (I finished the final few bits of it the other day), I’ve seen more insects living in it, and birds feeding on them, than I did before. Yay!

Use GLIB_VERSION_MIN_REQUIRED to avoid deprecation warnings

tl;dr: Define GLIB_VERSION_MIN_REQUIRED and GLIB_VERSION_MAX_ALLOWED in your meson.build to avoid deprecation warnings you don’t care about, or accidentally using GLib APIs which are newer than you want to use. You can add this to your library by copying gversionmacros.h and using its macros on public APIs in your header files.

With every new stable release, GLib adds and/or deprecates public API. If you are building a project against GLib, you probably don’t want to use the new APIs until you can reliably depend on a new enough version of GLib. Similarly, you want to be able to continue using the newly-deprecated APIs until you can reliably depend on the version of GLib which deprecated them.

In both cases, the alternative is for your project to add conditional compilation blocks which use some GLib symbols if building against the new version of GLib, and others if building against the old version. That’s lots of work, and no fun.

So to prevent projects using GLib APIs which are outside the range of GLib versions which those projects are tested to build and work against, GLib can emit deprecation warnings at compile time if APIs which are too new – or too old – are used.

You can enable this by defining GLIB_VERSION_MIN_REQUIRED and GLIB_VERSION_MAX_ALLOWED in your build environment. With Meson, add the following to your top-level meson.build, typically just after you check for the GLib dependency using dependency():

add_project_arguments(
  '-DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_46',
  '-DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_2_66',
  language: 'c')

The GLIB_VERSION_x symbols are provided by GLib, and there’s one for each stable release series. You can also use GLIB_VERSION_CUR_STABLE or GLIB_VERSION_PREV_STABLE to refer to the stable version of the copy of GLib you’re building against.

If undefined, both symbols default to the current stable version, meaning you get all new APIs and all deprecation warnings by default. This is good for keeping up to date with developments in GLib, but not so good if you are targeting an older distribution and don’t want to see all the latest deprecation warnings.

None of this is new; this blog post is your periodic reminder that this versioning functionality exists and you may benefit from using it.

Add this to your library too

It’s easy enough to add to other libraries, and should be useful in situations where your library is unlikely to break API for the foreseeable future, but could add or deprecate API with every release.

Simply copy and adapt gversionmacros.h, and use its macros against every symbol in a public header. You can use them for functions, types, macros and enums.

The downside is that you will need to update the version macros header for each new version of your library, to add macros for the new version. There’s no way round this within the header file, as C macros may not define additional macros. It may be possible to generate the header using an external script from Meson, though, if someone wants to automate it.

GUADEC 2020

tl;dr: The virtual GUADEC 2020 conference had negligible carbon emissions, on the order of 100× lower than the in-person 2019 conference. Average travel to the 2019 conference was 10% of each person’s annual carbon budget. 2020 had increased inclusiveness; but had the downside of a limited social scene. What can we do to get the best of both for 2021?

It’s been several weeks since GUADEC 2020 was held, and this release cycle of GNOME is coming to a close. It’s been an interesting year. The conference was a different experience from normal, and despite missing seeing everyone in person I thought it went very well. Many thanks to the organising team and especially the sysadmin team. I’m glad an online conference was possible, and happy that it allowed many people to attend who can’t normally do so. I hope we can incorporate the best parts of this year into future conferences.

Measuring things

During the conference, with the help of Bart, I collected some data about the resource consumption of the servers during GUADEC. After a bit of post-processing, it looks like the conference emitted on the order of 0.5–1tCO2e (tonnes of carbon dioxide equivalent, the measure of global warming potential). These emissions were from the conference servers (21% of the total), network traffic (55%), and an estimate of the power used by people’s home computers while watching talks (24%).

By way of contrast, there were estimated emissions of 110tCO2e for travel to and from GUADEC 2019 in Thessaloniki. Travel emissions are likely to be the bulk of the emissions from that conference (insufficient data is available to estimate the other costs, such as building use, food, events, etc.). Of those travel emissions, 98% were from flights, and 79% of attendees flew. The lowest emissions for a return flight were a bit under 0.3tCO2e, the highest were around 3tCO2e, and the mode was the bracket [0.3, 0.6)tCO2e.

This shows quite a contrast between in-person and virtual conferences — a factor of 100 difference in carbon emissions. The conference in Thessaloniki (which I’m focusing on because I’ve got data for it from the post-conference survey, not because it was particularly unusual) had 198 registered attendees, and modal transport emissions per attendee of 0.42tCO2e.

Does it matter?

The recommended personal carbon budget for 2019/2020 is 4.1tCO2e, and it decreases each year until we reach emissions which are compatible with 2°C of global warming in 2050. That means that everyone should only emit 4.1tCO2e or less, per year. Modal emissions of 0.42tCO2e per person attending the 2019 conference is 10% of their carbon budget.

Other emissions pathways give lower budgets sooner, and perhaps would be better goals (2°C of global warming is a lot).

Everyone is in charge of their own carbon budgeting, and how they choose to spend it. It’s possible to spend 10% of your annual budget on one conference and still come in under-budget for the year, but it’s not easy.

For this reason, and for the reasons of inclusiveness which we saw at GUADEC 2020, I hope we keep virtual participation as a first-class part of GUADEC in future. It would be good to explore ways of keeping the social aspects of an in-person conference without completely returning to the previous model of flying everyone to one place.

What about 2021?

I say ‘2021’, but please take this to mean ‘next time it’s safe to host an international in-person conference’.

Looking at the breakdown of transport emissions for GUADEC 2019 by mode, flights are the big target for emissions reductions (note the logarithmic scale):

GUADEC 2019 transport emissions by mode (note logarithmic scale)

Splitting the flights up by length shows that the obvious approach of encouraging international train travel instead of short-haul flights (emissions bins up to 1.2tCO2e/flight in the graph below) would not have got us more than 38% reduction in transport emissions for Thessaloniki, but that’s a pretty good start.

GUADEC 2019 total flight emissions breakdown by flight length (where flight length is bucketed by return emissions; a lower emissions bucket means a shorter return flight)

Would a model where we had per-continent or per-country in-person meetups, all attending a larger virtual conference, have significantly lower emissions? Would it bring back enough of the social atmosphere?

Something to think about for GUADEC 2021! If you have any comments or suggestions, or have spotted any mistakes in this analysis, please get in touch. The data is available here.

Thanks to Will Thompson for proofreading.

Controlling safety vs speed when writing files

GLib 2.65.1 has been released with a new g_file_set_contents_full() API which you should consider using instead of g_file_set_contents() for writing out a file — it’s a drop-in replacement. It provides two additional arguments, one to control the trade-off between safety and performance when writing the file, and one to set the file’s mode (permissions).

What’s wrong with g_file_set_contents()?

g_file_set_contents() has worked fine for many years (and will continue to do so). However, it doesn’t provide much flexibility. When writing a file out on Linux there are various ways to do it, some slower but safer — and some faster, but less safe, in the sense that if your program or the system crashes part-way through writing the file, the file might be left in an indeterminate state. It might be garbled, missing, empty, or contain only the old contents.

g_file_set_contents() chose a fairly safe (but not the fastest) approach to writing out files: write the new contents to a temporary file, fsync() it, and then atomically rename() the temporary file over the top of the old file. This approach means that other processes only ever see the old file contents or the new file contents (but not the partially-written new file contents); and it means that if there’s a crash, either the old file will exist or the new file will exist. However, it doesn’t guarantee that the new file will be safely stored on disk by the time g_file_set_contents() returns. It also has fewer guarantees if the old file didn’t exist (i.e. if the file is being written out for the first time).

In most situations, this is the right compromise. But not in all of them — so that’s why g_file_set_contents_full() now exists, to let the caller choose their own compromise.

Choose your own tradeoff

The level of safety/speed of g_file_set_contents() can be chosen using GFileSetContentsFlags.

Situations where your code might want a looser set of guarantees from the defaults might be when writing out cache files (where it typically doesn’t matter if they’re lost or corrupted), or when writing out large numbers of files where you’re going to call fsync() once after the whole lot (rather than once per file).

In these situations, you might choose G_FILE_SET_CONTENTS_NONE.

Conversely, your code might want a tighter set of guarantees when writing out files which are well-formed-but-incorrect when empty or filled with zeroes (as filling a file with zeroes is one of the failure modes of the existing g_file_set_contents() defaults, if the file is being created), or when writing valuable user data.

In these situations, you might choose G_FILE_SET_CONTENTS_CONSISTENT | G_FILE_SET_CONTENTS_DURABLE.

The default flags used by g_file_set_contents() are G_FILE_SET_CONTENTS_CONSISTENT | G_FILE_SET_CONTENTS_ONLY_EXISTING, which makes its definition:

gboolean
g_file_set_contents (const gchar  *filename,
                     const gchar  *contents,
                     gssize        length,
                     GError      **error)
{
  return g_file_set_contents_full (filename, contents, length,
                                   G_FILE_SET_CONTENTS_CONSISTENT |
                                   G_FILE_SET_CONTENTS_ONLY_EXISTING,
                                   0666, error);
}

Check your code

So, maybe now is the time to quickly grep your code for g_file_set_contents() calls, and see whether the default tradeoff is the right one in all the places you call it?

End of year thoughts

Inspired by others, I thought doing a retrospective on 2017 would be an interesting thing to look back on in a year’s time and see what’s changed.

Work things

December 2017 marked a year of me working for Endless. It’s been twelve months of fixing small bugs, maintaining some OS components, poking my nose into lower parts of the OS than I’m used to, and taking on one or two big projects. I spent a significant amount of time on a project to add new distribution features to libostree and flatpak. That’s something which will hopefully be rolling out in early 2018. It was good to be able to get fairly deeply involved with a new component at a lower level in the stack. More of that in 2018!

I also spent some of my time in 2017 picking up a bit more of the GLib maintenance workload. I’m not sure how much of a difference it’s made to the bug backlog, but it’s kept me occupied anyway.

Hobby things

For most of my working life, I’ve had the luxury of being able to work on FOSS software (mostly in the GNOME ecosystem) as my day job, and as a result, quite a few of my hobby projects are actually maintained during the day. The ones which aren’t have suffered during 2017, because time and energy are limited. I’ve been thinking of ways to ensure that code gets maintained, but haven’t come up with any good solutions in 2017. That’s one to carry over into 2018.

Trips

2017 was a bit less of a plane-heavy year than 2016, but some trips still happened:

  • FOSDEM, catching up with old friends and colleagues, and where the start of the current phase of GLib maintenance started.
  • A week of caving in South Wales, including a trip down the fantastic Dan-yr-Ogof cave (the short round), which included floating down an underground canal on an inflatable swimming pool ring.
  • A week of walking in the Glencoe area, where the weather was uncharacteristically cooperative, and the views were, predictably, pretty good.
  • A party in London to celebrate Endless’ 5th birthday. As always, it was good to spend quality time with my Endless colleagues in endless pubs.
  • Two weeks of caving in Austria, finding some new cave, and exploring further into existing cave. This is something I’m hoping to repeat in future.
  • GUADEC in Manchester, right on the back of the Austria trip (including some fun in posting a laptop to myself so I could have it at the conference). I gave a talk, which some people listened to. We also went on a walk in the Peak District, which was good fun (even if the weather was a bit grey).
  • Two weeks of long-distance trekking in the Svaneti region of Georgia. An excellent destination, with excellent cheese bread. We derived continual amusement from the guide’s dry humour, and the ‘helpful’ comments left by others on the trek information we were using. I did not get struck by lightning.
  • A long weekend in Stockholm to explore the city and catch up with friends. Stockholm has good running!

The outdoors

2017 has definitely been a year of taking advantage of living in the north of England.

  • Around 40 caving trips on weeknights and weekends, which have been interesting and (mostly) fun.
  • 12 fell races, a fun run along with a friend for part of their Bob Graham round, and my first ultra.
  • Running really took off for me: around 1300km run in total (and 57km of ascent), and about 150 hours of 2017 spent running.

Reading and listening

Gigs were a bit thin on the ground: despite there being plenty on in my local area, I always had something else to do. Despite that:

  • Insomnium were good, though I had to leave before the end because of trains.
  • Breabach were very good, and a band I hadn’t heard before going to the gig. Now a favourite.
  • Kreator sounded uncannily like their last live album, but were otherwise enjoyable.
  • Opeth were pretty fantastic, playing a good variety of new and old stuff.

I managed to read only 13 books in 2017, though that number is largely padded out by some short stories I read just to reach my yearly target. That’s not quite fair, though; I read 3250 pages in total. Most recommenable: Where Late the Sweet Birds Sang; most disappointing: Hiroshima.

Cave exploration in Austria

For once, this is going to be a non-technical post. I hope to share some of what I’ve been up to in my summer holidays this year.

In late July, I spent two weeks on the Löser plateau in Austria, as part of a long-running caving expedition exploring the caves up there. The plateau is a huge expanse of limestone, opposite the Dachstein, and it contains hundreds of caves of varying sizes. The same expedition has been going there every summer for the last 40 years, slowly working its way across the plateau, trying to find big and deep caves. This was the first time I’d joined them.

Credit: Chris Densham

Some brief background: What is caving? It’s a sport where people descend caves, generally to the bottom (or as deep as they can get), to see and map what is there. It typically involves a lot of water (less of that in Austria than the UK) and mud, cold temperatures (definitely cold in Austria), and technical rope work to descend and ascend vertical shafts (‘pitches’). It combines the skills of climbing, scrambling and surveying; and often requires unshakeable enthusiasm for prolonged physical misery. It’s good fun.

Credit: Luke Stangroom

This year, we focused primarily on two existing (and large) caves: Tunnock’s, and Balcony. I spent a number of my days down Balcony, at around -300m (that’s 300m vertically below the entrance of the cave). We explored various new bits of passage, including a 100m×80m×80m chamber which, sadly, was a dead end; but good fun to get to and explore. Other trips included setting up the ropes (’rigging’) in some bits of cave so they could be re-explored from previous years; and re-surveying some other pieces of passage where the original surveys were incorrect.

Credit: Brendan Hall

Aside from trips down Balcony, we spent some time prospecting for new caves, finding a couple of promising new ones, and another which looked promising then turned into a dead end after 100m of depth. Since I left, another few cave entrances (some new, some rediscovered from 2012) have been found, and leads have been pushed even further in the existing caves.

Credit: Brendan Hall

What are conditions like in the caves? Unlike caves in the UK, most of the ones on the Löser plateau are dry apart from one or two sections. It’s only very recently that exploration has got down to a depth which routinely sees water. There is some mud, but not as much as in the UK. However, what there is is thicker and more pervasive. There’s generally more sand than one sees in caves in the UK, which does a good job of gritting up equipment and hands (think about what happens whenever you go to the beach). The caves are cold, but not ludicrously so — a few of them are cold enough to maintain large ice columns, but I was warm enough in my UK caving gear without extra thermals.

Credit: Brendan Hall

Why do people do this expedition caving? Many reasons, but most commonly, because it takes you to interesting new places, it’s a technical challenge, it’s a physical challenge, and the other people who do it are good fun to be around.

Credit: Luke Stangroom

When not caving, due to tiredness, laziness or weather, people spent their time in the valley, relaxing and drawing up surveys of the sections of caves they’d recently explored (‘nerding’). There are various bits of software for this, which take the legs of dead-reckoned survey and tie them together, using error distribution through loop closures to increase accuracy. The results are pretty nifty, though it takes a while to get up to speed with the software and draw up your surveys efficiently.

Credit: http://expo.survex.com/1623/264/264.html

Caving’s a fun sport with opportunities to go places where literally no human has ever been before, if you take it far enough. It’s easy to get into, too. Read more updates from the expedition if you want.

DX hackfest: 2016 edition

By this time tomorrow, the 2016 edition of the GNOME developer experience hackfest will have started. This year, it’s in Brussels, kindly hosted by betacowork and ICAB.

betacowork-coworking-brussels-logo-web logo_white

We will be spending 3 days looking at a variety of things on the agenda to improve the lives of developers on GNOME, and make plans for the rest of the year. Watch out for updates on planet.gnome.org.

Thanks to the GNOME Foundation for sponsoring the travel for various people who are coming.

GnomeLogoHorizontal.svg

Collabora is sponsoring snacks throughout, and is sending 5 of us along for the hackfest. Thank you also to the other companies who are sending or letting people come — I know of Red Hat, Endless Mobile, Codethink and Canonical (please let me know if I’ve forgotten anyone!).

Codethink logo200px-Canonical_logo.svgRedHat.svgsplash-endless-mark-transCollabora logo

See people at FOSDEM afterwards?

Checking D-Bus API stability

Announcing dbus-deviation, a small tool and set of libraries for automatically checking whether a D-Bus interface has broken API between two releases of a piece of software, developed as part of my work at Collabora.

Why?

If you have a large software project, worked on by multiple developers, it might not be clear when D-Bus interfaces change. For example, they might be pulled in from another repository, or might be accidentally changed without anyone noticing.

Breaks in the D-Bus API of a project (when it’s supposed to be stable) are potentially worse than breaks in its C API, because they can only be detected at runtime — when client applications suddenly error out half-way through an operation because they’ve called a D-Bus method with the wrong argument type. At least with C API breaks, the compiler will catch the break.

(In this respect, I guess D-Bus APIs are actually a form of ABI — a runtime interface, rather than a compile-time interface.)

How?

dbus-deviation provides a utility called dbus-interface-diff, plus some GNU Make glue to plug it into your build system. It only works with git: for each tagged release of your project, it uses git-notes to store copies of all the D-Bus interfaces you care about, in their state at the time of that release. They’re stored as introspection XML; if you have that XML committed into the repository anyway, the git-note becomes a ref to the existing file blob, and takes up virtually no space at all. The dbus-interface-diff tool then does a diff between two XML files (for example, one stored for the most recent release, and the one currently in your working tree), and flags up any forwards- or backwards-incompatibilities.

What?

A backwards-incompatibility, as far as dbus-deviation is concerned, is one where existing clients will not work against new versions of the D-Bus service, for example because a method they use has been removed.

A forwards-incompatibility is one where new versions of clients may not work against old versions of the D-Bus service, for example because they use a method which has been added in a new version of the API.

Traditionally, projects care about preventing backwards-incompatible API changes, and don’t care so much about forwards-incompatibilities. dbus-deviation lets you set your desired stability policy.

Where?

dbus-deviation has a spartan website, a git repository, and bugs are stored using Bugs Everywhere in git; contact me in the comments or by e-mail if you want to report something. API documentation is available for the Python libraries underpinning it, which provide an AST and diff methods for D-Bus APIs.

To get using it, follow the instructions in the README file!

All feedback is very much welcome. One area I feel is still a little awkward is how dbus-deviation integrates with make dist — it forces use of a pre-push git hook to update the remote git-notes for the API signatures of newly pushed release tags. That needs to be set up by each developer who releases a project (using make dist) — any suggestions for improving this are welcome.

What next?

API stability checking for GIR APIs, perhaps? This one needs some more work.

Dynamic relocs, runtime overflows and -fPIC

While merrily compiling something a little while ago, my linker threw me this gem of an error message (using GNU gold):

error: libmumble.a(libmumble.o): requires dynamic R_X86_64_PC32 reloc against 'g_strdup' which may overflow at runtime; recompile with -fPIC

or, if you’re using GNU ld (the two linkers have different error messages for the same problem):

error: mumble.o: relocation R_X86_64_PC32 against symbol `g_strdup' can not be used when making a shared object; recompile with -fPIC

I recompiled everything with -fPIC, and magically the problem went away. But I didn’t understand why. I finally got a bit of time to investigate, so here we go.

tl;dr: This is caused by linking a shared library (which requires position-independent code, PIC) to a static library (which has not been compiled with PIC). You need to either link the shared library against a shared version of the static code (such as is produced automatically by libtool), or re-compile the static library with PIC enabled (-fPIC or -fpic).

To understand this, we need a brief introduction to the different types of linking, and how static objects and libraries differ from shared (or dynamic) objects and libraries. Let’s run with a minimal working example: two C files, shared.c and static.c. static.c is compiled to a static archive, libstatic.a (without position-independent code, PIC), and shared.c is compiled to a shared object, libshared.so, which links against libstatic.a.

What is a static object? It’s one where all symbol references are resolved at compile time. What’s a dynamic object? One where symbol references can be resolved at runtime. This means that dynamic objects have to have relocations performed as they’re loaded, which incurs a load-time penalty, but allows for shared libraries and symbol interpositing.

It is these relocations which cause the problem hinted at by the error message above. Each relocation is effectively a note to the runtime loader instructing it to replace a symbol reference in the dynamic object being loaded, with an address calculated at load time.

There are various types of relocations, defined by the platform ABI, as they are specific to the processor’s instruction set. For a more in-depth account of them, see Relocations, Relocations by Michael Guyver. In this case, the R_X86_64_PC32 relocation was chosen by the compiler, which is defined by the AMD64 ABI (Table 4.10). What does that mean? Each relocation type is essentially a mathematical function to define the address of a relocated symbol, given the information in various symbol, section and relocation tables in the dynamic object. The ABI defines R_X86_64_PC32 as \(\). Less succinctly, it is the offset of the referenced symbol, plus a constant adjustment (the addend) minus the offset of the relocation. This is all explained brilliantly by Michael Guyver on his blog.

So, with our example, we get the error:

$ make libshared.so
cc -Wall -c -o shared.o shared.c
cc -Wall -c -o static.o static.c
ar rcs libstatic.a static.o
cc -shared -o libshared.so shared.o libstatic.a
/usr/bin/ld: error: shared.o: requires dynamic R_X86_64_PC32 reloc against 'my_static_function' which may overflow at runtime; recompile with -fPIC
collect2: error: ld returned 1 exit status
make: *** [libshared.so] Error 1

If we look at the disassembly of the shared object:

$ objdump -d shared.o

shared.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <my_shared_function>:
   0:    55                       push   %rbp
   1:    48 89 e5                 mov    %rsp,%rbp
   4:    e8 00 00 00 00           callq  9 <my_shared_function+0x9>
   9:    5d                       pop    %rbp
   a:    c3                       retq

we can see at offset 4 that the callq instruction (calling my_static_function()) leaves 4 bytes for the address of the function to call (actually, callq is instruction-pointer-relative, so the 4 bytes are for the offset of the function from the RIP register).

As the code in libstatic.a is not PIC, it has to be loaded at a fixed offset in a process’ address space. The shared library, libshared.so, must be capable of being loaded anywhere in an address space. This would be fine if the callq instruction could take an absolute address to call, as the linker could substitute in the absolute address of my_static_function() (as is done on 32-bit systems). However, it cannot – it only has 4 bytes of operand to play with, rather than the 8 needed for a 64-bit address – so linking has to fail. And that’s why we get an error which talks about overflow.

What happens if libstatic.a is compiled with PIC enabled? Not a whole lot changes, actually. The disassembly of libstatic.a remains unchanged. shared.o gains a global object table (GOT) section and its relocation for the my_static_function() call changes from R_X86_64_PC32 to R_X86_64_PLT32 — a procedure linkage table (PLT) relocation using the GOT. We can see that in action in the disassembly of the successfully-linked libshared.so (with irrelevant bits omitted):

$ objdump --disassemble libshared.so 

libshared.so:     file format elf64-x86-64


Disassembly of section .plt:

00000000000005f0 <my_static_function@plt>:
 5f0:    ff 25 fa 13 00 00        jmpq   *0x13fa(%rip)        # 19f0 <_GLOBAL_OFFSET_TABLE_+0x28>
 5f6:    68 02 00 00 00           pushq  $0x2
 5fb:    e9 c0 ff ff ff           jmpq   5c0 <_init+0x20>

Disassembly of section .text:

00000000000006e8 <my_shared_function>:
 6e8:    55                       push   %rbp
 6e9:    48 89 e5                 mov    %rsp,%rbp
 6ec:    e8 ff fe ff ff           callq  5f0 <my_static_function@plt>
 6f1:    5d                       pop    %rbp
 6f2:    c3                       retq   
 6f3:    90                       nop

00000000000006f4 <my_static_function>:
 6f4:    55                       push   %rbp
 6f5:    48 89 e5                 mov    %rsp,%rbp
 6f8:    5d                       pop    %rbp
 6f9:    c3                       retq   
 6fa:    66 90                    xchg   %ax,%ax

Firstly, the callq instruction in my_shared_function() has acquired a non-zero operand. This is a constant offset from the instruction pointer at that instruction which references the entry for my_static_function() in the PLT, which we can see as my_static_function@plt in the .plt section. Rather than being the code for the my_static_function(), this is actually a ‘trampoline’ which loads the address of my_static_function() from the GOT, then jumps to it. The GOT is set up by the runtime loader, and allows for the address of my_static_function() to be changed; for example when relocating it, or when interpositing a different version using LD_PRELOAD. By default, the GOT entry for my_static_function() will point to the implementation in the .text section, as linked in from libstatic.a.

This trampolining through a PLT and GOT is the standard solution for producing position independent code, and demonstrates three things:

  • Exported functions incur a runtime cost (in the PLT) on every call. This can be eliminated for private symbols (or internal calls to public symbols, with -Bsymbolic), but not (easily) for public ones, as explained by Ian Lance Taylor. This cost is only three instructions; as they change control flow, they could be relatively expensive, but are probably also catered specifically for in modern superscalar 64-bit processors, as the majority of the code they execute will do indirect function calls this way. So the cost can be safely ignored for all but rather specific use cases.
  • Position independent code is easy to achieve, and the indirection it requires brings other benefits like the ever-useful LD_PRELOAD, used by developer tools everywhere.
  • Marking internal functions as static is important, because ELF exports functions by default, so internal function calls end up being indirected through the PLT if you omit the static modifier. (Though note that none of the functions here could have been marked as such, as they were all in different compilation units.)

So in summary:

  • The “requires dynamic R_X86_64_PC32 reloc against ‘mumble’ which may overflow at runtime; recompile with -fPIC” error is caused by attempting to link a shared library against a static object.
    • One solution is to compile a position-independent version of the static object. libtool does this automatically, so why aren’t you using libtool?
    • Another (highly related) solution is to link against a shared version of the static object.
  • This isn’t an issue on 32-bit systems because PIC is possible by default on those systems, since instruction operands are wide enough to contain absolute symbol addresses .
  • Compiling with position independent code introduces a procedure linkage table (PLT) and global offset table (GOT) for each object file, which are very hard to eliminate if you want to avoid the (small) function call overhead they introduce.
    • So you should avoid PIC if compiling for constrained targets like embedded devices.
    • But use it otherwise (e.g. on desktop systems) for the flexibility (the use of shared libraries!) and security (address space layout randomisation) it affords.

Source code for the example here is available on gitlab in the public domain.

Travelling in Honduras

Having just spent 7 weeks in Honduras, working and travelling, I thought it might be useful to document some of the things I’ve learned about the country.

In my experience, Honduras has three distinct areas: the north (Caribbean) side where English is spoken moderately commonly, and many people go to learn to dive (especially on the Bay Islands); the three major cities (Tegucigalpa, San Pedro Sula and La Ceiba) where tourism infrastructure is practically non-existent, pollution is high and crime is high; and the rest of the countryside, which is pleasant, safe (for the most part) and has little tourism infrastructure.

Lightning on the cloudy mountains around Tegucigalpa at night.I spent 5 weeks in the capital (Tegucigalpa) and saw the bad side of Honduras. It is not a safe city to walk around, even in the richer areas, so you have to drive everywhere. I hadn’t previously realised how much I value being able to walk the streets and go where I please without probability of being robbed at gunpoint. Despite its security problems, Tegus was a reasonable-ish place to be. It has all the amenities of a big city — clubbing, for example, there is just as grim as in England, except with more Latin music. There is nothing for tourists to see, and they should only use it as a transport hub (since it has one of the country’s two major airports, and is a major bus terminal) or as a base to explore the much-nicer Valle de Ángeles, La Tigra national park, and Comayagua nearby.

Tegucigalpa demonstrates the two major problems which Honduras suffers from: a huge imbalance in the distribution of wealth, and endemic corruption in government and the police force. These have knock-on effects on everything else. The rich live in enclosed neighbourhoods with high walls, barbed wire, electric fences, and armed private security. They drive luxury 4×4s and have lives which would be considered privileged in Europe. The poor live in shacks which line the roads and are stacked up the hillsides. There is a huge amount of gang crime: it seems that most of the drugs passing from South America to the USA come through Honduras. This gang crime contributes hugely to Honduras’ murder rate, making it officially one of the most dangerous countries in the world — although if you’re not involved in a gang, you’re as safe as in other Central American countries. A lot of this crime goes unpunished, both because the police are unable to tackle the gangs, and also because they’re corrupt. It is the army which enforces the law here.

One of the many building-piers on Utila.The Bay Islands are completely different. I spent a week on Utila, and it was a safe, friendly place, quite different from Tegucigalpa. Its summer climate is hot (30?) and humid (up to 80% relative humidity, with very little wind), which I found unbearable at times. Still, it is easy to get to, has excellent diving opportunities, and caters well for someone who wants to party every night. It’s quite drug-friendly.

The rest of the country is mostly small villages and farmland. There isn’t much tourism infrastructure, but travel is easy and cheap on ‘collectivo’ and chicken buses (old, reappropriated US school buses; less gaudily decorated than in Guatemala). Most villages don’t have much to offer other than colonial architecture and old churches (and a lot of auto repair shops). A few are more popular: Gracias, Lempira; and Copán Ruinas.

Gracias, Lempira in the sun.

Gracias has more quaint architecture than most places, and is next to Celaque national park, home of Honduras’ tallest mountain (Cerro Las Minas). Worth a visit if you like cloud forests, bird watching or hiking in general. Summitting Cerro Las Minas normally takes two days, but an experienced (and fit — it’s a steep mountain) hiker can do it in 7 hours.

A stone face in the ruins at Copán.Copán Ruinas is the gateway to the country’s Mayan ruins, which are definitely worth a visit. Very well preserved hieroglyphics, and lots of wildlife (including a Macaw breeding programme). If you visit Copán Ruinas, seeing the ruins will take half a day, and there is little else to do in the town unless you plan in advance with a local tour company to do a trek or horse ride. I didn’t, so I don’t know what they’re like.

Infrastructure is what Honduras lacks. Its roads are full of potholes (leading to its infamous crazy driving), there are frequent (roughly once a week) power outages and internet outages. None of the tap water is potable and drainage often runs straight onto the street (which in turn expedites damage to the roads). Building and maintaining infrastructure in such a mountainous country is tricky, but it’s necessary.

With the benefit of hindsight, there are a few things I would do differently if I came to Honduras again. Quite a few of them are the standard recommendations for travelling in Central/South America anyway:

  • If you can afford it, hire a car or motorbike (the latter are incredibly popular here). Having your own transport gives you a lot of freedom and safety. Get a vehicle suited to off-road driving: even if you don’t end up on a dirt track (which is quite possible if one of the few major roads is closed due to landslides), there are nasty speed bumps throughout the country which chew up cars with low ground clearance.
  • If you can’t, use collectivo buses, which are safe and, while the routes aren’t listed anywhere online or on paper, generally follow major roads. Any local will know about them. They run very frequently.
  • Find out which areas of a city are considered safe, and which aren’t. If you stick to the safe areas and use common sense, everything will be fine. If you go to an unsafe area, you’re likely to be robbed or kidnapped. For example, even the locals in Tegus don’t venture to Comayaguela. The hotels aren’t always in the safe areas, especially in Tegucigalpa — definitely avoid anything in the Comayaguela area.
  • Don’t plan to do much hiking. It’s not a particularly popular pastime here, so while there are many ‘national parks’, they mostly exist to protect the cloud forests. There are some nice trails in some (for example, La Tigra and Celaque), but don’t expect too much. If you’re interested in birds, however, Honduras is supposed to be pretty good; there are hotels dedicated to bird watching around La Ceiba.
  • If you go to the Bay Islands to dive, have a contingency plan in case of illness (which would prevent you from diving). When I was there, several people I knew got colds and ended up doing absolutely nothing for a week until they got better.
  • Don’t try and plan a tight itinerary in advance, as unexpected transport problems might throw it off. Internet access is easy to come by in Honduras (especially 3G), so make things up as you go along. Factor in plenty of time for making travel connections, as few of the bus times are synchronised.
  • Aside from touristy places (like Copán Ruinas), Honduras doesn’t do European-style hostels. You’re going to have to look at hotels, but there are cheap ones.
  • Similarly, don’t expect to send any postcards. In my experience, they’re hard to find, and harder to send. Post offices are like gold dust.
  • Don’t trust the websites describing most bus routes in Honduras (apart from the huge companies like Hedman Alas). Even medium-sized Honduran companies don’t do websites well, or keep them updated. Phone the bus company up instead, or ask a local.