Lame, nasm and text relocations (textrels)

By Alasdair Lumsden on 26 Mar 2011

Lame, nasm and text relocations

Well, this took some debugging.

I’ve filed it all in a nasm bug report. To cut a long story short, if you compile LAME with Nasm 2.09, you’ll end up with TEXTRELs in the resultant libmp3lame.so.

What is a TEXTREL you may ask? Something bad! It stops the code being fully PIC (position independent), which stops the shared object being loaded into memory once and mapped multiple times. But worse, it causes Solaris ld to explode when linking:

gcc -shared -Wl,-h -Wl,libmp3lame.so.0 -o .libs/libmp3lame.so.0.0.0 .libs/VbrTag.o .libs/bitstream.o .libs/encoder.o .libs/fft.o .libs/gain_analysis.o .libs/id3tag.o .libs/lame.o .libs/newmdct.o .libs/presets.o .libs/psymodel.o .libs/quantize.o .libs/quantize_pvt.o .libs/reservoir.o .libs/set_get.o .libs/tables.o .libs/takehiro.o .libs/util.o .libs/vbrquantize.o .libs/version.o .libs/mpglib_interface.o -Wl,-z -Wl,allextract ../libmp3lame/i386/.libs/liblameasmroutines.a ../libmp3lame/vector/.libs/liblamevectorroutines.a ../mpglib/.libs/libmpgdecoder.a -Wl,-z -Wl,defaultextract -lm -lsocket -lnsl -lc -maccumulate-outgoing-args
Text relocation remains referenced
against symbol offset in file
 0x6e ../libmp3lame/i386/.libs/liblameasmroutines.a(choose_table.o)
 0x75 ../libmp3lame/i386/.libs/liblameasmroutines.a(choose_table.o)
 0x9a ../libmp3lame/i386/.libs/liblameasmroutines.a(choose_table.o)
 0xa1 ../libmp3lame/i386/.libs/liblameasmroutines.a(choose_table.o)
 0xa8 ../libmp3lame/i386/.libs/liblameasmroutines.a(choose_table.o)
 0x12b ../libmp3lame/i386/.libs/liblameasmroutines.a(choose_table.o)
 0x133 ../libmp3lame/i386/.libs/liblameasmroutines.a(choose_table.o)
 0x1a0 ../libmp3lame/i386/.libs/liblameasmroutines.a(choose_table.o)
 0x1aa ../libmp3lame/i386/.libs/liblameasmroutines.a(choose_table.o)
 0x1b4 ../libmp3lame/i386/.libs/liblameasmroutines.a(choose_table.o)
 0x1c2 ../libmp3lame/i386/.libs/liblameasmroutines.a(choose_table.o)
 0x24c ../libmp3lame/i386/.libs/liblameasmroutines.a(choose_table.o)
 0x25d ../libmp3lame/i386/.libs/liblameasmroutines.a(choose_table.o)
 0x39 ../libmp3lame/i386/.libs/liblameasmroutines.a(fft3dn.o)
 0x56 ../libmp3lame/i386/.libs/liblameasmroutines.a(fft3dn.o)
 0x128 ../libmp3lame/i386/.libs/liblameasmroutines.a(fft3dn.o)
 0x142 ../libmp3lame/i386/.libs/liblameasmroutines.a(fft3dn.o)
 0x26e ../libmp3lame/i386/.libs/liblameasmroutines.a(fft3dn.o)
 0x2b9 ../libmp3lame/i386/.libs/liblameasmroutines.a(fft3dn.o)
 0x2d6 ../libmp3lame/i386/.libs/liblameasmroutines.a(fft3dn.o)
 0x398 ../libmp3lame/i386/.libs/liblameasmroutines.a(fft3dn.o)
 0x4ce ../libmp3lame/i386/.libs/liblameasmroutines.a(fft3dn.o)
 0x2c ../libmp3lame/i386/.libs/liblameasmroutines.a(fftsse.o)
 0x7a ../libmp3lame/i386/.libs/liblameasmroutines.a(fftsse.o)
 0x88 ../libmp3lame/i386/.libs/liblameasmroutines.a(fftsse.o)
 0xc4 ../libmp3lame/i386/.libs/liblameasmroutines.a(fftsse.o)
 0xd9 ../libmp3lame/i386/.libs/liblameasmroutines.a(fftsse.o)
 0xe7 ../libmp3lame/i386/.libs/liblameasmroutines.a(fftsse.o)
 0x1d0 ../libmp3lame/i386/.libs/liblameasmroutines.a(fftsse.o)
 0x1e4 ../libmp3lame/i386/.libs/liblameasmroutines.a(fftsse.o)
 0x20b ../libmp3lame/i386/.libs/liblameasmroutines.a(fftsse.o)
 0x219 ../libmp3lame/i386/.libs/liblameasmroutines.a(fftsse.o)
t1l 0x189 ../libmp3lame/i386/.libs/liblameasmroutines.a(choose_table.o)
largetbl 0xde ../libmp3lame/i386/.libs/liblameasmroutines.a(choose_table.o)
largetbl 0x105 ../libmp3lame/i386/.libs/liblameasmroutines.a(choose_table.o)
largetbl 0x10f ../libmp3lame/i386/.libs/liblameasmroutines.a(choose_table.o)
table23 0x245 ../libmp3lame/i386/.libs/liblameasmroutines.a(choose_table.o)
table56 0x256 ../libmp3lame/i386/.libs/liblameasmroutines.a(choose_table.o)
ld: fatal: relocations remain against allocatable but non-writable sections
collect2: ld returned 1 exit status

The way to fix the problem is to use NASM 2.08 or earlier, or wait until the bug gets fixed (although they might point their finger at LAME). I’m going to try yasm instead of nasm and see if that works, as an alternative.

If you don’t care about TEXTRELs, on Linux you don’t have to do anything (GNU ld allows them by default), but on Solaris you can tell the Solaris linker to allow impure text segments by adding “-mimpure-text -lrt” to your LDFLAGS. Or, you can use the GNU linker. This is quite hard, but I wrote a blog post about it.