aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorklondike <klondike@xiscosoft.es>2010-11-12 18:32:30 +0100
committerklondike <klondike@xiscosoft.es>2010-11-12 18:32:30 +0100
commitb499b0f83177293b546cc99aaf3319d72c7add67 (patch)
treec28adcf00d43475234f06967b2db43ce2cb1fe67 /html/pic-fix-guide.html
parentmerging with CVS tree (diff)
downloadhardened-docs-b499b0f83177293b546cc99aaf3319d72c7add67.tar.gz
hardened-docs-b499b0f83177293b546cc99aaf3319d72c7add67.tar.bz2
hardened-docs-b499b0f83177293b546cc99aaf3319d72c7add67.zip
updating html previews
Diffstat (limited to 'html/pic-fix-guide.html')
-rw-r--r--html/pic-fix-guide.html877
1 files changed, 877 insertions, 0 deletions
diff --git a/html/pic-fix-guide.html b/html/pic-fix-guide.html
new file mode 100644
index 0000000..179eab0
--- /dev/null
+++ b/html/pic-fix-guide.html
@@ -0,0 +1,877 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<link title="new" rel="stylesheet" href="http://www.gentoo.org/css/main.css" type="text/css">
+<link REL="shortcut icon" HREF="http://www.gentoo.org/favicon.ico" TYPE="image/x-icon">
+<link rel="search" type="application/opensearchdescription+xml" href="http://www.gentoo.org/search/www-gentoo-org.xml" title="Gentoo Website">
+<link rel="search" type="application/opensearchdescription+xml" href="http://www.gentoo.org/search/forums-gentoo-org.xml" title="Gentoo Forums">
+<link rel="search" type="application/opensearchdescription+xml" href="http://www.gentoo.org/search/bugs-gentoo-org.xml" title="Gentoo Bugzilla">
+<link rel="search" type="application/opensearchdescription+xml" href="http://www.gentoo.org/search/packages-gentoo-org.xml" title="Gentoo Packages">
+<link rel="search" type="application/opensearchdescription+xml" href="http://www.gentoo.org/search/archives-gentoo-org.xml" title="Gentoo List Archives">
+<title>Gentoo Linux Documentation
+--
+ HOWTO Locate and Fix .text Relocations (TEXTRELs)</title>
+</head>
+<body style="margin:0px;" bgcolor="#ffffff"><table width="100%" border="0" cellspacing="0" cellpadding="0">
+<tr><td valign="top" height="125" bgcolor="#45347b"><a href="http://www.gentoo.org/"><img border="0" src="http://www.gentoo.org/images/gtop-www.jpg" alt="Gentoo Logo"></a></td></tr>
+<tr><td valign="top" align="right" colspan="1" bgcolor="#ffffff"><table border="0" cellspacing="0" cellpadding="0" width="100%"><tr>
+<td width="99%" class="content" valign="top" align="left">
+<br><h1>HOWTO Locate and Fix .text Relocations (TEXTRELs)</h1>
+<form name="contents" action="http://www.gentoo.org">
+<b>Content</b>:
+ <select name="url" size="1" OnChange="location.href=form.url.options[form.url.selectedIndex].value" style="font-family:sans-serif,Arial,Helvetica"><option value="#doc_chap1">1. Introduction</option>
+<option value="#doc_chap2">2. Finding broken object code</option>
+<option value="#doc_chap3">3. Dissecting broken object code</option>
+<option value="#doc_chap4">4. Finding the broken source code</option>
+<option value="#doc_chap5">5. How to write PIC (in theory)</option>
+<option value="#doc_chap6">6. Cookie cutter PIC fixes</option>
+<option value="#doc_chap7">7. How to fix broken PIC (in practice)</option>
+<option value="#doc_chap8">8. References</option></select>
+</form>
+<p class="chaphead"><a name="doc_chap1"></a><span class="chapnum">1.
+ </span>Introduction</p>
+<p>
+You should make sure to read the <a href="pic-guide.xml">Introduction to
+Position Independent Code</a> before tackling this guide.
+</p>
+<p>
+This guide is x86-centric for now. The reason being, the majority of broken
+object files are due to poorly written x86 assembly stemming from the simple
+fact that the x86 architecture has so few registers. Other architectures have
+a large enough register set that they can reserve a register as the "PIC
+register" without incurring a performance hit. Every architecture has to be
+mindful of PIC and its implications, x86 just happens to be the dominant
+architecture at the moment in the 'desktop' world of open source.
+</p>
+<p>
+We will update for non-x86 as we aquire details and useful examples.
+</p>
+<p class="chaphead"><a name="doc_chap2"></a><span class="chapnum">2.
+ </span>Finding broken object code</p>
+<p>
+Before you can start fixing something, you got to make sure it's broken first,
+right? For this reason, we've developed a suite of tools named <a href="http://www.gentoo.org/proj/en/hardened/pax-utils.xml">PaX Utilities</a>. If you are not
+familiar with these utilities, you should read the <a href="http://www.gentoo.org/proj/en/hardened/pax-utils.xml">PaX Utilities Guide</a> now. Gentoo
+users can simply do <span class="code" dir="ltr">emerge pax-utils</span>. Non-Gentoo users should be able
+to find a copy of the source tarball in the <span class="path" dir="ltr">distfiles</span> on a <a href="http://www.gentoo.org/main/en/mirrors.xml">Gentoo Mirror</a>. Once you have the PaX
+Utilities setup on your system, we can start playing around with
+<span class="code" dir="ltr">scanelf</span>.
+</p>
+<p>
+Keep in mind that although these utilities are named PaX Utilities, they
+certainly do not require PaX or anything else like that on your system.
+The name is a historical artifact and want of a better name, has stuck.
+</p>
+<p>
+Let's see if your system has any broken files.
+</p>
+<a name="doc_chap2_pre1"></a><table class="ntable" width="100%" cellspacing="0" cellpadding="0" border="0">
+<tr><td bgcolor="#7a5ada"><p class="codetitle">Code Listing2.1: Scan your system</p></td></tr>
+<tr><td bgcolor="#eeeeff" align="left" dir="ltr"><pre>
+$ <span class="code-input">scanelf -lpqt</span>
+TEXTREL /usr/lib/opengl/xorg-x11/lib/libGL.so.1.2
+TEXTREL /usr/lib/libSDL-1.2.so.0.7.2
+TEXTREL /usr/lib/libdv.so.4.0.2
+TEXTREL /usr/lib/libsmpeg-0.4.so.0.1.3
+TEXTREL /usr/lib/libOSMesa.so.4.0
+TEXTREL /usr/lib/libxvidcore.so.4.1
+</pre></td></tr>
+</table>
+<p>
+Ideally, scanelf should not display anything, but on an x86 system, this is
+rarely the case. Here we can see six libraries with TEXTRELs in them.
+To quickly find out what package these files come from, Gentoo users can
+<span class="code" dir="ltr">emerge portage-utils</span> and use <span class="code" dir="ltr">qfile</span>.
+</p>
+<a name="doc_chap2_pre2"></a><table class="ntable" width="100%" cellspacing="0" cellpadding="0" border="0">
+<tr><td bgcolor="#7a5ada"><p class="codetitle">Code Listing2.2: Determine the broken packages</p></td></tr>
+<tr><td bgcolor="#eeeeff" align="left" dir="ltr"><pre>
+$ <span class="code-input">qfile `scanelf -qylpF%F#t`</span>
+media-libs/libdv (/usr/lib/libdv.so.4.0.2)
+media-libs/libsdl (/usr/lib/libSDL-1.2.so.0.7.2)
+media-libs/smpeg (/usr/lib/libsmpeg-0.4.so.0.1.3)
+media-libs/xvid (/usr/lib/libxvidcore.so.4.1)
+x11-base/xorg-x11 (/usr/lib/opengl/xorg-x11/lib/libGL.so.1.2)
+x11-base/xorg-x11 (/usr/lib/libOSMesa.so.4.0)
+</pre></td></tr>
+</table>
+<p>
+Now that we know the offenders, we have a choice. We can file a bug upstream
+(who generally don't care unless you can provide a fix), file a bug in the
+<a href="http://bugs.gentoo.org/">Gentoo Bugzilla</a> (which is a nice
+lazy cop out), or we can fix it ourselves (that is why you're reading this
+guide right?). You should double check that the package version you have
+installed is the latest upstream has to offer and the latest version your
+distro has to offer. Who knows, maybe you can get lucky and someone else has
+already fixed it. If you wish to get feedback on your work, feel free to
+contact the <a href="mailto:hardened@gentoo.org">Gentoo hardened team</a>.
+</p>
+<p class="secthead"><a name="doc_chap2_sect2">"False" Positives</a></p>
+<p>
+Sometimes you may come across a package which contains a mountain of TEXTRELs
+with seemingly no relation to assembler. This may simply be because the
+objects were not properly compiled with the appropriate PIC flag. The fix is
+quite simple: make sure every object file that is linked into the final shared
+object is compiled with the appropriate PIC flag (typically -fPIC).
+</p>
+<p>
+For example, let's look at the silc-plugin package. It builds up a few
+modules, but only compiles some of the objects with -fPIC that are linked into
+the final libsilc_core.so module. The output of scanelf here is quite
+extensive!
+</p>
+<a name="doc_chap2_pre3"></a><table class="ntable" width="100%" cellspacing="0" cellpadding="0" border="0">
+<tr><td bgcolor="#7a5ada"><p class="codetitle">Code Listing2.3: Run scanelf on silc-plugin</p></td></tr>
+<tr><td bgcolor="#eeeeff" align="left" dir="ltr"><pre>
+$ <span class="code-input">scanelf -qT /usr/lib/irssi/modules/libsilc_core.so | wc -l</span>
+10734
+$ <span class="code-input">scanelf -qT /usr/lib/irssi/modules/libsilc_core.so</span>
+...
+ libsilc_core.so: silc_client_ftp_ask_name [0xD542C] in silc_client_receive_new_id [0xD5380]
+ libsilc_core.so: silc_client_run_one [0xD55CA] in silc_client_receive_new_id [0xD5380]
+ libsilc_core.so: silc_id_payload_parse [0xD5842] in silc_client_packet_parse_type [0xD57B0]
+ libsilc_core.so: fgetc@@GLIBC_2.0 [0xD5857] in silc_client_packet_parse_type [0xD57B0]
+...
+</pre></td></tr>
+</table>
+<p>
+A TEXTREL on glibc's fgetc() function!? Either people are calling fgetc() from
+assembler (and should be shot), or something else is going on. A good rule of
+thumb is that if it seems like just about every function/variable reference
+causes a TEXTREL and it is all done in C code, then the file was not built as
+PIC. Just review the build output and see if the command to compile it was
+invoked with -fPIC. If not, go fix the build system as you do not need to dig
+into the source. Dodged the bullet this time!
+</p>
+<p class="chaphead"><a name="doc_chap3"></a><span class="chapnum">3.
+ </span>Dissecting broken object code</p>
+<p>
+So we have identified some broken libraries, and we want to fix them. The
+trouble is, shared library code can be huge. They can have thousands of
+functions which come from thousands of object files and thousands of source
+code files which total megabytes in size (source code and compiled objects).
+Where the hell do we start!? Once again, Mighty Mouse^W^W<span class="code" dir="ltr">scanelf</span> is
+here to save the day. Before we dive into source code, lets check out a few
+libraries.
+</p>
+<p class="secthead"><a name="doc_chap3_sect2">Dissect libsmpeg</a></p>
+<a name="doc_chap3_pre1"></a><table class="ntable" width="100%" cellspacing="0" cellpadding="0" border="0">
+<tr><td bgcolor="#7a5ada"><p class="codetitle">Code Listing3.1: Scan libsmpeg</p></td></tr>
+<tr><td bgcolor="#eeeeff" align="left" dir="ltr"><pre>
+<span class="code-comment">[The output has been truncated from about 35 lines]</span>
+$ <span class="code-input">scanelf -qT /usr/lib/libsmpeg-0.4.so.0.1.3</span>
+ libsmpeg-0.4.so.0.1.3: (memory/fake?) [0x2FB3C] in cpu_flags [0x2FB10]
+ libsmpeg-0.4.so.0.1.3: (memory/fake?) [0x2FB42] in cpu_flags [0x2FB10]
+ libsmpeg-0.4.so.0.1.3: (memory/fake?) [0x2FB55] in IDCT_mmx [0x2FB48]
+ libsmpeg-0.4.so.0.1.3: (memory/fake?) [0x2FB84] in IDCT_mmx [0x2FB48]
+ /usr/lib/libsmpeg-0.4.so.0.1.3
+</pre></td></tr>
+</table>
+<p>
+The output here tells us that the <span class="emphasis">cpu_flags</span> and the <span class="emphasis">IDCT_mmx</span>
+functions are to blame for our TEXTRELs. The first field indicates that this
+is poor usage of memory references. Unfortunately, the symbolic name of the
+memory being referenced has not been retained in the object code (probably
+because the code is hand written assembly), so we need to do a little more
+digging. This is where the offset addresses come in to play along with the
+<span class="code" dir="ltr">objdump</span> utility from the <span class="emphasis">binutils</span> package. The first address
+(e.g. 0x2FB3C) is the offset of the TEXTREL while the second address is the
+offset of the function (e.g. 0x2FB10). Get used to this because the behavior
+of not retaining the symbol name is quite common.
+</p>
+<a name="doc_chap3_pre2"></a><table class="ntable" width="100%" cellspacing="0" cellpadding="0" border="0">
+<tr><td bgcolor="#7a5ada"><p class="codetitle">Code Listing3.2: Dissecting libsmpeg</p></td></tr>
+<tr><td bgcolor="#eeeeff" align="left" dir="ltr"><pre>
+$ <span class="code-input">objdump -d /usr/lib/libsmpeg-0.4.so.0.1.3</span>
+...
+ 2fb0f: 90 nop
+
+<span class="code-input">0002fb10 &lt;cpu_flags&gt;:</span>
+ 2fb10: 9c pushf
+ 2fb11: 58 pop %eax
+...
+ 2fb32: 60 pusha
+ 2fb33: b8 01 00 00 00 mov $0x1,%eax
+ 2fb38: 0f a2 cpuid
+ <span class="code-input">2fb3a: 89 15 d0 d3 03 00 mov %edx,0x3d3d0</span>
+ 2fb40: 61 popa
+ <span class="code-input">2fb41: a1 d0 d3 03 00 mov 0x3d3d0,%eax</span>
+ 2fb46: c3 ret
+ 2fb47: 90 nop
+...
+</pre></td></tr>
+</table>
+<p>
+As you can see here, the two lines picked out in the body of <span class="emphasis">cpu_flags</span>
+have absolute memory references. In this case, they both refer to memory
+location <span class="emphasis">0x3d3d0</span>. Since this object code may be loaded into any
+address, using an aboslute reference obviously won't fly. That means
+everytime libsmpeg is loaded into memory, the dynamic loader has to rewrite
+the <span class="emphasis">0x3d3d0</span> to the actual calculated address on the fly.
+</p>
+<p class="secthead"><a name="doc_chap3_sect3">Dissect libdv</a></p>
+<a name="doc_chap3_pre3"></a><table class="ntable" width="100%" cellspacing="0" cellpadding="0" border="0">
+<tr><td bgcolor="#7a5ada"><p class="codetitle">Code Listing3.3: Scan libdv</p></td></tr>
+<tr><td bgcolor="#eeeeff" align="left" dir="ltr"><pre>
+<span class="code-comment">[The output has been truncated from about 180 lines]</span>
+$ <span class="code-input">scanelf -qT /usr/lib/libdv.so.4.0.2</span>
+ libdv.so.4.0.2: (memory/fake?) [0x14AA9] in dv_parse_ac_coeffs_pass0 [0x14A84]
+ libdv.so.4.0.2: (memory/fake?) [0x14C28] in dv_parse_ac_coeffs_pass0 [0x14A84]
+ libdv.so.4.0.2: (memory/fake?) [0x14C8A] in dv_parse_video_segment [0x14C6F]
+ libdv.so.4.0.2: (memory/fake?) [0x14CA6] in dv_parse_video_segment [0x14C6F]
+ libdv.so.4.0.2: (memory/fake?) [0x15248] in _dv_idct_block_mmx [0x15210]
+ libdv.so.4.0.2: (memory/fake?) [0x152BE] in _dv_idct_block_mmx [0x15210]
+ libdv.so.4.0.2: (memory/fake?) [0x1583D] in _dv_dct_88_block_mmx [0x157F8]
+ libdv.so.4.0.2: (memory/fake?) [0x15847] in _dv_dct_88_block_mmx [0x157F8]
+ libdv.so.4.0.2: (memory/fake?) [0x15F91] in _dv_dct_248_block_mmx [0x15F58]
+ libdv.so.4.0.2: (memory/fake?) [0x15FE6] in _dv_dct_248_block_mmx [0x15F58]
+ libdv.so.4.0.2: (memory/fake?) [0x163D3] in _dv_rgbtoycb_mmx [0x163C8]
+ libdv.so.4.0.2: (memory/fake?) [0x163DD] in _dv_rgbtoycb_mmx [0x163C8]
+ libdv.so.4.0.2: dv_vlc_class_index_mask [0x149A7] in dv_decode_vlc [0x14998]
+ libdv.so.4.0.2: dv_vlc_class_index_rshift [0x149B0] in dv_decode_vlc [0x14998]
+ libdv.so.4.0.2: dv_vlc_classes [0x149B9] in dv_decode_vlc [0x14998]
+ libdv.so.4.0.2: dv_vlc_index_mask [0x149C4] in dv_decode_vlc [0x14998]
+ libdv.so.4.0.2: sign_mask [0x149EB] in dv_decode_vlc [0x14998]
+ libdv.so.4.0.2: sign_mask [0x14A5D] in __dv_decode_vlc [0x14A1C]
+ libdv.so.4.0.2: sign_mask [0x14B82] in dv_parse_ac_coeffs_pass0 [0x14A84]
+ libdv.so.4.0.2: dv_vlc_class_lookup5 [0x14A2F] in __dv_decode_vlc [0x14A1C]
+ libdv.so.4.0.2: dv_parse_ac_coeffs_pass0 [0x14E03] in dv_parse_video_segment [0x14C6F]
+ libdv.so.4.0.2: dv_parse_ac_coeffs [0x14E51] in dv_parse_video_segment [0x14C6F]
+ libdv.so.4.0.2: dv_quant_offset [0x14E69] in _dv_quant_88_inverse_x86 [0x14E5C]
+ libdv.so.4.0.2: dv_quant_offset [0x14FB3] in _dv_quant_x86 [0x14FA4]
+ /usr/lib/libdv.so.4.0.2
+</pre></td></tr>
+</table>
+<p>
+Again, we can see that many functions (like <span class="emphasis">dv_parse_ac_coeffs_pass0</span>
+and <span class="emphasis">_dv_idct_block_mmx</span>) have absolute memory references. What we also
+see is that a bunch of functions which refer to variables. For example,
+<span class="emphasis">dv_decode_vlc</span> misuses the variable <span class="emphasis">dv_vlc_class_index_mask</span> while
+<span class="emphasis">dv_parse_video_segment</span> misuses the variable <span class="emphasis">dv_parse_ac_coeffs</span>.
+Much easier to locate the problem in the source code when you have the symbol
+name.
+</p>
+<p class="secthead"><a name="doc_chap3_sect4">Dissect libSDL</a></p>
+<a name="doc_chap3_pre4"></a><table class="ntable" width="100%" cellspacing="0" cellpadding="0" border="0">
+<tr><td bgcolor="#7a5ada"><p class="codetitle">Code Listing3.4: Scan libSDL</p></td></tr>
+<tr><td bgcolor="#eeeeff" align="left" dir="ltr"><pre>
+<span class="code-comment">[The output has been truncated from about 50 lines]</span>
+$ <span class="code-input">scanelf -qT /usr/lib/libSDL-1.2.so.0.7.2</span>
+ libSDL-1.2.so.0.7.2: (memory/fake?) [0x4E213] in _ConvertMMXpII32_24RGB888 [0x4E210]
+ libSDL-1.2.so.0.7.2: (memory/fake?) [0x4E29E] in _ConvertMMXpII32_16RGB565 [0x4E29B]
+ libSDL-1.2.so.0.7.2: (memory/fake?) [0x4E3F6] in _ConvertMMXpII32_16BGR555 [0x4E3F3]
+ libSDL-1.2.so.0.7.2: (memory/fake?) [0x4E402] in _ConvertMMXpII32_16RGB555 [0x4E3FF]
+ libSDL-1.2.so.0.7.2: (memory/fake?) [0x4E555] in _Hermes_X86_CPU [0x4E529]
+ libSDL-1.2.so.0.7.2: _copy_row [0x316A2] in SDL_SoftStretch [0x313C0]
+ libSDL-1.2.so.0.7.2: _mmxreturn [0x4E4FB] in _ConvertMMXpII32_16RGB555 [0x4E3FF]
+ libSDL-1.2.so.0.7.2: _x86return [0x4E590] in _ConvertX86p16_16BGR565 [0x4E560]
+ libSDL-1.2.so.0.7.2: _x86return [0x4EE99] in _ConvertX86p32_16BGR555 [0x4EDCA]
+ libSDL-1.2.so.0.7.2: _x86return [0x4EF4D] in _ConvertX86p32_8RGB332 [0x4EE9D]
+ /usr/lib/libSDL-1.2.so.0.7.2
+</pre></td></tr>
+</table>
+<p>
+Doesn't seem to be anything new here. Poor memory usage in functions like
+<span class="emphasis">_ConvertMMXpII32_24RGB888</span> and no symbol name which means it's probably
+pure hand written assembler. The <span class="emphasis">SDL_SoftStretch</span> function misuses the
+symbol <span class="emphasis">_copy_row</span> and since the symbol name has been retained, it's
+probably inline assembly code.
+</p>
+<p class="chaphead"><a name="doc_chap4"></a><span class="chapnum">4.
+ </span>Finding the broken source code</p>
+<p>
+We've identified the functions and sometimes the variables which are causing
+us such headaches. Before we can actually fix them though, we have to narrow
+down the source code to the offending lines. Since we know the function
+names and either the symbol name or a relative position in the function, we
+should be able to focus our efforts quite easily.
+</p>
+<p class="secthead"><a name="doc_chap4_sect2">libsmpeg source dive</a></p>
+<p>
+Let's start with libsmpeg. We know that both the <span class="emphasis">cpu_flags</span> and
+<span class="emphasis">IDCT_mmx</span> functions are broken. But where are they defined?
+</p>
+<a name="doc_chap4_pre1"></a><table class="ntable" width="100%" cellspacing="0" cellpadding="0" border="0">
+<tr><td bgcolor="#7a5ada"><p class="codetitle">Code Listing4.1: Searching libsmpeg source</p></td></tr>
+<tr><td bgcolor="#eeeeff" align="left" dir="ltr"><pre>
+$ <span class="code-input">tar zxf smpeg-0.4.4.tar.gz</span>
+$ <span class="code-input">cd smpeg-0.4.4.tar.gz</span>
+
+<span class="code-comment">[Find the cpu_flags function]</span>
+$ <span class="code-input">grep -Rl cpu_flags *</span>
+video/mmxflags_asm.S
+video/parseblock.cpp
+$ <span class="code-input">grep cpu_flags video/mmxflags_asm.S</span>
+.globl cpu_flags
+ .type cpu_flags,@function <span class="code-comment">&lt;-- here is what we want</span>
+cpu_flags:
+ jz cpu_flags.L1 # Processor is 386
+ je cpu_flags.L1
+cpu_flags.L1:
+ .size cpu_flags,.Lfe1-cpu_flags
+
+<span class="code-comment">[Find the IDCT_mmx function]</span>
+$ <span class="code-input">grep -Rl IDCT_mmx *</span>
+video/parseblock.cpp
+video/mmxidct_asm.S
+$ <span class="code-input">grep IDCT_mmx video/mmxidct_asm.S</span>
+.globl IDCT_mmx
+ .type IDCT_mmx,@function <span class="code-comment">&lt;-- here is what we want</span>
+IDCT_mmx:
+ .size IDCT_mmx,.Lfe1-IDCT_mmx
+</pre></td></tr>
+</table>
+<p>
+As we suspected, both the <span class="emphasis">cpu_flags</span> and the <span class="emphasis">IDCT_mmx</span> functions
+are written in pure assembly code. This makes tracking down the unamed
+memory reference easier because the source code should closely match the
+output of <span class="code" dir="ltr">objdump</span>. If we review the output from earlier, we know the
+<span class="emphasis">cpuid</span> instruction is used. Since it isn't a common instruction, we
+search for it in the source code.
+</p>
+<a name="doc_chap4_pre2"></a><table class="ntable" width="100%" cellspacing="0" cellpadding="0" border="0">
+<tr><td bgcolor="#7a5ada"><p class="codetitle">Code Listing4.2: Find cpuid in cpu_flags</p></td></tr>
+<tr><td bgcolor="#eeeeff" align="left" dir="ltr"><pre>
+$ <span class="code-input">grep -A 8 cpuid video/mmxflags_asm.S</span>
+ cpuid
+
+ movl %edx,flags
+
+ popa
+
+ movl flags,%eax
+
+cpu_flags.L1:
+</pre></td></tr>
+</table>
+<p>
+In GNU assembler, registers are prefixed with a <span class="emphasis">%</span> and constants are
+prefixed with a <span class="emphasis">$</span>, that <span class="emphasis">flags</span> looks suspicious. It also lines
+up well with the <span class="code" dir="ltr">objdump</span> output from earlier. So what is <span class="emphasis">flags</span>?
+</p>
+<a name="doc_chap4_pre3"></a><table class="ntable" width="100%" cellspacing="0" cellpadding="0" border="0">
+<tr><td bgcolor="#7a5ada"><p class="codetitle">Code Listing4.3: What is 'flags'?</p></td></tr>
+<tr><td bgcolor="#eeeeff" align="left" dir="ltr"><pre>
+$ <span class="code-input">grep -C 2 flags video/mmxflags_asm.S</span>
+.data
+ .align 16
+ .type flags,@object
+flags: .long 0
+
+.text
+</pre></td></tr>
+</table>
+<p>
+Seems <span class="emphasis">flags</span> is a data variable local to <span class="path" dir="ltr">mmxflags_asm.S</span>
+which functions access with absolute memory references rather than relative.
+Now we are pretty much done. That's all there is to it. We started with the
+library <span class="path" dir="ltr">libsmpeg.so</span> and tracked it back to the function
+<span class="emphasis">cpu_flags</span> and the variable <span class="emphasis">flags</span> in the
+<span class="path" dir="ltr">video/mmxflags_asm.S</span> file. That wasn't so hard now was it? :)
+</p>
+<p>
+If we analyze the <span class="emphasis">IDCT_mmx</span> function, we find a similar trend.
+</p>
+<a name="doc_chap4_pre4"></a><table class="ntable" width="100%" cellspacing="0" cellpadding="0" border="0">
+<tr><td bgcolor="#7a5ada"><p class="codetitle">Code Listing4.4: IDCT_mmx snippets</p></td></tr>
+<tr><td bgcolor="#eeeeff" align="left" dir="ltr"><pre>
+<span class="code-comment">[Local variables]</span>
+.data
+ .align 8
+ .type x4546454645464546,@object
+ .size x4546454645464546,8
+<span class="code-input">x4546454645464546</span>:
+ .long 0x45464546,0x45464546
+
+ .align 8
+ .type x61f861f861f861f8,@object
+ .size x61f861f861f861f8,8
+<span class="code-input">x61f861f861f861f8</span>:
+ .long 0x61f861f8,0x61f861f8
+
+ .align 8
+ .type scratch1,@object
+ .size scratch1,8
+<span class="code-input">scratch1</span>:
+ .long 0,0
+
+<span class="code-comment">[Absolute memory references]</span>
+.text
+...
+ psraw $1, %mm5 /* t90=t93 */
+ pmulhw <span class="code-input">x4546454645464546</span>,%mm0 /* V35 */
+ psraw $1, %mm2 /* t97 */
+...
+ psubsw %mm2, %mm1 /* V32 ; free mm2 */
+ pmulhw <span class="code-input">x61f861f861f861f8</span>,%mm1 /* V36 */
+ psllw $1, %mm7 /* t107 */
+...
+ movq 8*3(%esi), %mm7
+ psraw $4, %mm4
+ movq %mm2, <span class="code-input">scratch1</span> /* out1 */
+</pre></td></tr>
+</table>
+<p class="secthead"><a name="doc_chap4_sect3">libSDL source dive</a></p>
+<p>
+Again, before we jump into how to fix these, lets analyze a few more source
+files to get a better handle on identifying problematic code.
+</p>
+<a name="doc_chap4_pre5"></a><table class="ntable" width="100%" cellspacing="0" cellpadding="0" border="0">
+<tr><td bgcolor="#7a5ada"><p class="codetitle">Code Listing4.5: Broken _ConvertMMXpII32_24RGB888 in libSDL code</p></td></tr>
+<tr><td bgcolor="#eeeeff" align="left" dir="ltr"><pre>
+<span class="code-comment">[objdump of _ConvertMMXpII32_24RGB888 memory reference]</span>
+<span class="code-input">0004e210 &lt;_ConvertMMXpII32_24RGB888&gt;:</span>
+ <span class="code-input">4e210: 0f 6f 35 50 55 05 00 movq 0x55550,%mm6</span>
+ 4e217: 0f ef ff pxor %mm7,%mm7
+
+<span class="code-comment">[_ConvertMMXpII32_24RGB888 is defined in src/hermes/mmxp2_32.asm]</span>
+ SECTION .data
+ALIGN 8
+;; Constants for conversion routines
+mmx32_rgb888_mask dd 00ffffffh,00ffffffh
+...
+ SECTION .text
+_ConvertMMXpII32_24RGB888: <span class="code-comment">start of function 0x4E210</span>
+ ; set up mm6 as the mask, mm7 as zero
+ movq mm6, qword [mmx32_rgb888_mask] <span class="code-comment">memory reference 0x4E213</span>
+ pxor mm7, mm7
+</pre></td></tr>
+</table>
+<p>
+Simple enough, the <span class="emphasis">_ConvertMMXpII32_24RGB888</span> function refers to the
+<span class="emphasis">mmx32_rgb888_mask</span> variable.
+</p>
+<a name="doc_chap4_pre6"></a><table class="ntable" width="100%" cellspacing="0" cellpadding="0" border="0">
+<tr><td bgcolor="#7a5ada"><p class="codetitle">Code Listing4.6: Broken SDL_SoftStretch in libSDL code</p></td></tr>
+<tr><td bgcolor="#eeeeff" align="left" dir="ltr"><pre>
+<span class="code-comment">[SDL_SoftStretch is defined in src/video/SDL_stretch.c]</span>
+int SDL_SoftStretch(SDL_Surface *src, SDL_Rect *srcrect,
+ SDL_Surface *dst, SDL_Rect *dstrect)
+{
+...
+#ifdef __GNUC__
+ __asm__ __volatile__ (
+ "call _copy_row"
+ : "=&amp;D" (u1), "=&amp;S" (u2)
+ : "0" (dstp), "1" (srcp)
+ : "memory" );
+#else
+</pre></td></tr>
+</table>
+<p>
+Another straight forward bug. An absolute reference to the <span class="emphasis">_copy_row</span>
+variable in assembly. If we were to let gcc handle the <span class="emphasis">_copy_row</span>
+reference instead though ...
+</p>
+<p class="chaphead"><a name="doc_chap5"></a><span class="chapnum">5.
+ </span>How to write PIC (in theory)</p>
+<p class="secthead"><a name="doc_chap5_sect1">Rules of thumb</a></p>
+<p>
+Now we know what broken code looks like. We can point out issues in code and
+confidently declare "that crap is broken". While this is a good thing, it
+certainly doesn't help much if no one knows how it's supposed to be written.
+Let's start with some rules of thumb.
+</p>
+<p>General rules</p>
+<ul>
+ <li>Do not mix PIC and non-PIC object code</li>
+ <li>Shared libraries contain PIC objects</li>
+ <li>Static libraries contain non-PIC objects (normal/non-PIE systems only)</li>
+ <li>Let gcc figure out the details whenever possible (e.g. inline asm)</li>
+ <li>Use the stack for loading of large masks instead of variables</li>
+ <li>Do not clobber the PIC register when generating PIC objects</li>
+</ul>
+<p>x86-specific rules</p>
+<ul>
+ <li>Use @GOT relocations when using external symbols</li>
+ <li>Use @GOTOFF relocations when using local symbols</li>
+</ul>
+<p class="secthead"><a name="doc_chap5_sect2">PIC registers by architecture</a></p>
+<table class="ntable">
+ <tr>
+<td class="infohead"><b>arch</b></td>
+<td class="infohead"><b>register</b></td>
+</tr>
+ <tr>
+<td class="tableinfo">blackfin</td>
+<td class="tableinfo">P3</td>
+</tr>
+ <tr>
+<td class="tableinfo">frv</td>
+<td class="tableinfo">GR15</td>
+</tr>
+ <tr>
+<td class="tableinfo">hppa</td>
+<td class="tableinfo">r19</td>
+</tr>
+ <tr>
+<td class="tableinfo">x86</td>
+<td class="tableinfo">ebx</td>
+</tr>
+</table>
+<p class="chaphead"><a name="doc_chap6"></a><span class="chapnum">6.
+ </span>Cookie cutter PIC fixes</p>
+<p class="secthead"><a name="doc_chap6_sect1">Don't use the PIC register</a></p>
+<p>
+If you come across code which uses the PIC register in some inline assembly,
+one fix may be to simply use a different register. For example, the x86
+architecture has 6 general purpose registers (<span class="emphasis">eax</span>, <span class="emphasis">ebx</span>,
+<span class="emphasis">ecx</span>, <span class="emphasis">edx</span>, <span class="emphasis">esi</span>, <span class="emphasis">edi</span>). If the code uses just
+<span class="emphasis">eax</span> and <span class="emphasis">ebx</span>, just change all references to <span class="emphasis">ebx</span> to
+<span class="emphasis">ecx</span> and you're done!
+</p>
+<p>
+A cleaner fix might be to just let gcc allocate the registers accordingly. If
+the inline assembly doesn't actually care which registers it uses, change the
+references from <span class="emphasis">ebx</span> to <span class="emphasis">r</span> in the clobber list, and refer to the
+variable by number.
+</p>
+<p>
+Or, if the assembly uses an instruction which always clobbers <span class="emphasis">ebx</span> (e.g.
+<span class="emphasis">cpuid</span>), simply hide the value in another register (like <span class="emphasis">esi</span>).
+</p>
+<p>
+If all else fails, you can fall back to the slow push/pop <span class="emphasis">ebx</span> on the
+stack method.
+</p>
+<a name="doc_chap6_pre1"></a><table class="ntable" width="100%" cellspacing="0" cellpadding="0" border="0">
+<tr><td bgcolor="#7a5ada"><p class="codetitle">Code Listing6.1: Just don't use the PIC register</p></td></tr>
+<tr><td bgcolor="#eeeeff" align="left" dir="ltr"><pre>
+<span class="code-comment">/* change this code from */</span>
+asm("
+ mov %0, %%eax
+ mov %1, %%ebx
+ add %%eax, %%ebx
+ " : : "m"(input1), "m"(input2) : "eax" "ebx");
+
+<span class="code-comment">/* to this functionality equivalent version */</span>
+asm("
+ mov %0, %%eax
+ mov %1, %%ecx
+ add %%eax, %%ecx
+ " : : "m"(input1), "m"(input2) : "eax" "ecx");
+</pre></td></tr>
+</table>
+<a name="doc_chap6_pre2"></a><table class="ntable" width="100%" cellspacing="0" cellpadding="0" border="0">
+<tr><td bgcolor="#7a5ada"><p class="codetitle">Code Listing6.2: Let gcc allocate registers</p></td></tr>
+<tr><td bgcolor="#eeeeff" align="left" dir="ltr"><pre>
+<span class="code-comment">/* change this code from */</span>
+asm("
+ mov %2, %%eax
+ mov %3, %%ebx
+ add %%eax, %%ebx
+ " : "=a"(output1) "=b"(output2) : "m"(input1), "m"(input2));
+
+<span class="code-comment">/* to this functionality equivalent version */</span>
+asm("
+ mov %2, %0
+ mov %3, %1
+ add %0, %1
+ " : "=r"(output1) "=r"(output2) : "m"(input1), "m"(input2));
+</pre></td></tr>
+</table>
+<a name="doc_chap6_pre3"></a><table class="ntable" width="100%" cellspacing="0" cellpadding="0" border="0">
+<tr><td bgcolor="#7a5ada"><p class="codetitle">Code Listing6.3: Hide the PIC register</p></td></tr>
+<tr><td bgcolor="#eeeeff" align="left" dir="ltr"><pre>
+asm("cpuid" : : : "eax", "ebx", "ecx", "edx");
+
+<span class="code-comment">/* can be written to hide ebx */</span>
+asm("
+ movl %%ebx, %%edi
+ cpuid
+ movl %%edi, %%ebx
+ " : : : "eax", "ecx", "edx", "edi");
+
+<span class="code-comment">/* or a slower version using the stack */</span>
+asm("
+ pushl %%ebx
+ cpuid
+ popl %%ebx
+ " : : : "eax", "ecx", "edx");
+</pre></td></tr>
+</table>
+<p class="secthead"><a name="doc_chap6_sect2">MMX/SSE masks</a></p>
+<p>
+A lot of x86 MMX/SSE code loads bitmasks from local variables since they need
+to fill up a register which is larger (MMX/64bits or SSE/128bits) than the
+native bitsize (x86/32bits). They do this by defining the mask in
+consecutive bytes in memory and then having the cpu load the data from the
+memory region.
+</p>
+<p>
+One way to get around this is by being creative with the stack. Rather than
+use an absolute memory reference for the mask, push a bunch of 32bit values
+onto the stack and use the address specified by the <span class="emphasis">esp</span> register.
+Once you're finished, just add a constant to <span class="emphasis">esp</span> rather than popping
+off since you don't care about the actual values once they are loaded into
+the MMX/SSE registers.
+</p>
+<a name="doc_chap6_pre4"></a><table class="ntable" width="100%" cellspacing="0" cellpadding="0" border="0">
+<tr><td bgcolor="#7a5ada"><p class="codetitle">Code Listing6.4: Load masks into registers via stack</p></td></tr>
+<tr><td bgcolor="#eeeeff" align="left" dir="ltr"><pre>
+<span class="code-comment">/* Load masks from memory (causes TEXTRELs) */</span>
+ .data
+m0X000000: .byte 0, 0, 0, 0, 0, 0, 255, 0
+ .text
+movq m0X000000, %mm5
+
+<span class="code-comment">/* Load mask from stack (no TEXTRELs)*/</span>
+pushl $0x00FF0000
+pushl $0x00000000
+movq (%esp), %mm5
+addl 8, %esp
+</pre></td></tr>
+</table>
+<p class="secthead"><a name="doc_chap6_sect3">Let gcc worry about it</a></p>
+<p>
+A lot of inline assembly is written with the symbol names placed right in the
+code. Rather than trying to write custom code to handle PIC in assembly, just
+let gcc worry about it. Pass in the symbol via the input operand list as a
+memory constraint ("m") and gcc will handle all the rest.
+</p>
+<a name="doc_chap6_pre5"></a><table class="ntable" width="100%" cellspacing="0" cellpadding="0" border="0">
+<tr><td bgcolor="#7a5ada"><p class="codetitle">Code Listing6.5: How to make gcc worry about it</p></td></tr>
+<tr><td bgcolor="#eeeeff" align="left" dir="ltr"><pre>
+unsigned long long a_mmx_mask = 0xf8007c00ffea0059ULL;
+void somefunction()
+{
+ <span class="code-comment">/* Common (but incorrect) method for loading masks */</span>
+ asm("pmullw a_mmx_mask, %%mm0" : : );
+
+ <span class="code-comment">/* The correct way is to let gcc do it */</span>
+ asm("pmullw %0, %%mm0" : : "m"(a_mmx_mask));
+}
+</pre></td></tr>
+</table>
+<p>
+If your get a warning/error about one of the memory inputs needing to be an
+lvalue, then this usually means you're trying to pass in a pointer to an
+array/structure rather than the memory location itself. Fixing this may be as
+simple as dereferencing the variable in the constraint list rather than in the
+assembly itself.
+</p>
+<p class="secthead"><a name="doc_chap6_sect4">Thunk it in assembly</a></p>
+<p>
+Hand written assembly sometimes need to access variables (whether they be
+local or global). Since none of the previous tricks will work, you just need
+to grind your teeth and dig in to write real PIC references yourself using
+the GOT. Make sure you keep in mind the first rule of thumb: Do not mix PIC
+and non-PIC object code. This probably will require the hand written
+assembly be preprocessed before it is assembled, so an assembly source file
+with a <span class="emphasis">.s</span> suffix will not work. It needs to be <span class="emphasis">.S</span>.
+</p>
+<p>
+Also keep in mind that using @GOTOFF will return the variable while using @GOT
+will return a pointer to the variable. So accessing a variable with @GOT will
+require two steps.
+</p>
+<a name="doc_chap6_pre6"></a><table class="ntable" width="100%" cellspacing="0" cellpadding="0" border="0">
+<tr><td bgcolor="#7a5ada"><p class="codetitle">Code Listing6.6: How to refer to variables via the GOT</p></td></tr>
+<tr><td bgcolor="#eeeeff" align="left" dir="ltr"><pre>
+#ifdef __PIC__
+
+# undef __i686 /* gcc builtin define gets in our way */
+# define MUNG_LOCAL(sym) sym ## @GOTOFF(%ebx)
+# define MUNG_EXTERN(sym) sym ## @GOT(%ebx)
+# define DEREF_EXTERN(reg) movl (reg), reg
+# define INIT_PIC() \
+ call __i686.get_pc_thunk.bx ; \
+ addl $_GLOBAL_OFFSET_TABLE_, %ebx
+
+#else
+
+# define MUNG_LOCAL(sym) sym
+# define MUNG_EXTERN(sym) sym
+# define DEREF_EXTERN(reg)
+# define INIT_PIC()
+
+#endif
+
+...
+some_function:
+...
+ <span class="code-comment">/* needs to be before first memory reference */</span>
+ INIT_PIC()
+...
+ movl MUNG_EXTERN(some_external_variable), %eax
+ DEREF_EXTERN(%eax)
+...
+ movl %eax, MUNG_LOCAL(some_local_variable)
+...
+
+#ifdef __PIC__
+ .section .gnu.linkonce.t.__i686.get_pc_thunk.bx,"ax",@progbits
+.globl __i686.get_pc_thunk.bx
+ .hidden __i686.get_pc_thunk.bx
+ .type __i686.get_pc_thunk.bx,@function
+__i686.get_pc_thunk.bx:
+ movl (%esp), %ebx
+ ret
+#endif
+</pre></td></tr>
+</table>
+<table class="ncontent" width="100%" border="0" cellspacing="0" cellpadding="0"><tr><td bgcolor="#bbffbb"><p class="note"><b>Note: </b>
+Usage of <span class="emphasis">ebx</span> as the register to do relative addressing is not required,
+it is just common convention. The above examples could just as easily be done
+by using <span class="emphasis">ecx</span> or <span class="emphasis">edx</span>.
+</p></td></tr></table>
+<p>
+Since we hide the PIC details behind the preprocessor define <span class="emphasis">__PIC__</span>,
+we know that the correct code will be generated for both the PIC and non-PIC
+cases.
+</p>
+<p>
+The <span class="emphasis">__i686.get_pc_thunk.bx</span> function is a standard method for acquiring
+the address of the GOT at runtime and storing the result in <span class="emphasis">ebx</span>. The
+funky name is what gcc uses by convention when generating PIC objects, so we
+too use the same name. The <span class="emphasis">@GOT</span> and <span class="emphasis">@GOTOFF</span> notation tells the
+assembler where to find the variables in memory. The <span class="emphasis">.section
+.gnu.linkonce.t</span> is useful because it tells the linker to only include one
+instance of this function in the final object code. So if you have multiple
+files which declare this same function which are compiled and linked into the
+same final library, the linker will discard all duplicate instances of the
+function thus saving space (which is always a good thing).
+</p>
+<p class="chaphead"><a name="doc_chap7"></a><span class="chapnum">7.
+ </span>How to fix broken PIC (in practice)</p>
+<p>
+So if the previous code snippets were broken, what should they look like you
+may wonder. Well let's find out.
+</p>
+<p class="secthead"><a name="doc_chap7_sect2">Fix libsmpeg</a></p>
+<a name="doc_chap7_pre1"></a><table class="ntable" width="100%" cellspacing="0" cellpadding="0" border="0">
+<tr><td bgcolor="#7a5ada"><p class="codetitle">Code Listing7.1: Fixing cpu_flags in libsmpeg by rewriting it</p></td></tr>
+<tr><td bgcolor="#eeeeff" align="left" dir="ltr"><pre>
+<span class="code-comment">[Non-PIC Version]</span>
+.type flags,@object
+flags: .long 0
+...
+ pusha
+ movl $1,%eax
+ cpuid
+ movl %edx,flags
+ popa
+ movl flags,%eax
+
+
+<span class="code-comment">[PIC Version]</span>
+ pushl %ebx
+ movl $1,%eax
+ cpuid
+ movl %edx,%eax
+ popl %ebx
+</pre></td></tr>
+</table>
+<a name="doc_chap7_pre2"></a><table class="ntable" width="100%" cellspacing="0" cellpadding="0" border="0">
+<tr><td bgcolor="#7a5ada"><p class="codetitle">Code Listing7.2: Fixing IDCT_mmx in libsmpeg by using relative addressing</p></td></tr>
+<tr><td bgcolor="#eeeeff" align="left" dir="ltr"><pre>
+<span class="code-comment">[Non-PIC Version]</span>
+ pmulhw x5a825a825a825a82, %mm1
+
+
+<span class="code-comment">[PIC Version]</span>
+#ifdef __PIC__
+# undef __i686 /* gcc define gets in our way */
+ call __i686.get_pc_thunk.bx
+ addl $_GLOBAL_OFFSET_TABLE_, %ebx
+#endif
+...
+ pmulhw x5a825a825a825a82@GOTOFF(%ebx), %mm1
+...
+#ifdef __PIC__
+ .section .gnu.linkonce.t.__i686.get_pc_thunk.bx,"ax",@progbits
+.globl __i686.get_pc_thunk.bx
+ .hidden __i686.get_pc_thunk.bx
+ .type __i686.get_pc_thunk.bx,@function
+__i686.get_pc_thunk.bx:
+ movl (%esp), %ebx
+ ret
+#endif
+</pre></td></tr>
+</table>
+<p class="secthead"><a name="doc_chap7_sect3">Fix libSDL</a></p>
+<a name="doc_chap7_pre3"></a><table class="ntable" width="100%" cellspacing="0" cellpadding="0" border="0">
+<tr><td bgcolor="#7a5ada"><p class="codetitle">Code Listing7.3: Fixing _ConvertMMXpII32_24RGB888 in libSDL</p></td></tr>
+<tr><td bgcolor="#eeeeff" align="left" dir="ltr"><pre>
+<span class="code-comment">[Non-PIC Version]</span>
+mmx32_rgb888_mask dd 00ffffffh,00ffffffh
+...
+ movq mm6, qword [mmx32_rgb888_mask]
+
+
+<span class="code-comment">[PIC Version]</span>
+%macro _push_immq_mask 1
+ push dword %1
+ push dword %1
+%endmacro
+%macro load_immq 2
+ _push_immq_mask %2
+ movq %1, [esp]
+%endmacro
+%define mmx32_rgb888_mask 00ffffffh
+...
+ load_immq mm6, mmx32_rgb888_mask
+ CLEANUP_IMMQ_LOADS(1)
+</pre></td></tr>
+</table>
+<a name="doc_chap7_pre4"></a><table class="ntable" width="100%" cellspacing="0" cellpadding="0" border="0">
+<tr><td bgcolor="#7a5ada"><p class="codetitle">Code Listing7.4: Fixing SDL_SoftStretch in libSDL</p></td></tr>
+<tr><td bgcolor="#eeeeff" align="left" dir="ltr"><pre>
+<span class="code-comment">[Non-PIC Version]</span>
+ __asm__ __volatile__ (
+ "call _copy_row"
+ : "=&amp;D" (u1), "=&amp;S" (u2)
+ : "0" (dstp), "1" (srcp)
+ : "memory" );
+
+
+<span class="code-comment">[PIC Version]</span>
+ __asm__ __volatile__ (
+ "call *%4"
+ : "=&amp;D" (u1), "=&amp;S" (u2)
+ : "0" (dstp), "1" (srcp), "r" (&amp;_copy_row)
+ : "memory" );
+</pre></td></tr>
+</table>
+<p class="chaphead"><a name="doc_chap8"></a><span class="chapnum">8.
+ </span>References</p>
+<ul>
+ <li>thanks to the PaX team for holding my hand</li>
+ <li><a href="http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html">GCC Inline Assembly HOWTO</a></li>
+ <li>
+<a href="http://nasm.sourceforge.net/">NASM</a>'s Documentation on <a href="http://nasm.sourceforge.net/doc/html/nasmdoc6.html#section-6.5.2">ELF shared libraries</a>
+</li>
+ <li>Linkers and Loaders <a href="http://www.iecc.com/linker/linker08.html">chapter 8</a> and <a href="http://www.iecc.com/linker/linker10.html">chapter 10</a>
+</li>
+</ul>
+<br><br>
+</td>
+<td width="1%" bgcolor="#dddaec" valign="top"><table border="0" cellspacing="4px" cellpadding="4px">
+<tr><td class="topsep" align="center"><p class="altmenu"><a title="View a printer-friendly version" class="altlink" href="http://www.gentoo.org/proj/en/hardened/pic-fix-guide.xml?style=printable">Print</a></p></td></tr>
+<tr><td class="topsep" align="center"><p class="alttext">Updated August 19, 2007</p></td></tr>
+<tr><td class="topsep" align="left"><p class="alttext"><b>Summary: </b>A guide for tracking down and fixing .text relocations (TEXTRELs)</p></td></tr>
+<tr><td align="left" class="topsep"><p class="alttext">
+ <a href="mailto:vapier@gentoo.org" class="altlink"><b>Mike Frysinger</b></a>
+<br><i>Author</i><br><br>
+ <a href="mailto:solar@gentoo.org" class="altlink"><b>solar</b></a>
+<br><i>Author</i><br><br>
+ <a href="mailto:pageexec@freemail.hu" class="altlink"><b>The PaX team</b></a>
+<br><i>Contributor</i><br><br>
+ <a href="mailto:kevquinn@gentoo.org" class="altlink"><b>Kevin F. Quinn</b></a>
+<br><i>Contributor</i><br></p></td></tr>
+<tr lang="en"><td align="center" class="topsep">
+<p class="alttext"><b>Donate</b> to support our development efforts.
+ </p>
+<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+<input type="hidden" name="cmd" value="_xclick"><input type="hidden" name="business" value="paypal@gentoo.org"><input type="hidden" name="item_name" value="Gentoo Linux Support"><input type="hidden" name="item_number" value="1000"><input type="hidden" name="image_url" value="http://www.gentoo.org/images/paypal.png"><input type="hidden" name="no_shipping" value="1"><input type="hidden" name="return" value="http://www.gentoo.org"><input type="hidden" name="cancel_return" value="http://www.gentoo.org"><input type="image" src="http://images.paypal.com/images/x-click-but21.gif" name="submit" alt="Donate to Gentoo">
+</form>
+</td></tr>
+<tr lang="en"><td align="center"><iframe src="http://sidebar.gentoo.org" scrolling="no" width="125" height="850" frameborder="0" style="border:0px padding:0x" marginwidth="0" marginheight="0"><p>Your browser does not support iframes.</p></iframe></td></tr>
+</table></td>
+</tr></table></td></tr>
+<tr><td colspan="2" align="right" class="infohead">
+Copyright 2001-2010 Gentoo Foundation, Inc. Questions, Comments? <a class="highlight" href="http://www.gentoo.org/main/en/contact.xml">Contact us</a>.
+</td></tr>
+</table></body>
+</html>