{"id":258,"date":"2025-11-22T12:37:26","date_gmt":"2025-11-22T12:37:26","guid":{"rendered":"https:\/\/haco.club\/?p=258"},"modified":"2025-11-22T12:37:26","modified_gmt":"2025-11-22T12:37:26","slug":"pie-relocation-tagging-addresses","status":"publish","type":"post","link":"https:\/\/haco.club\/?p=258","title":{"rendered":"PIE Relocation: Tagging Addresses"},"content":{"rendered":"\n<p>In a Position-Independent Executable (PIE), absolute addresses aren&#8217;t &#8220;tagged&#8221; directly within the machine code. Instead, the&nbsp;<strong>linker creates a separate list of instructions and data locations that need fixing<\/strong>, and this list is stored in a special section of the binary called the&nbsp;<strong>relocation table<\/strong>.<\/p>\n\n\n\n<p>The dynamic loader uses this table at runtime to patch the code with the correct memory addresses once the binary&#8217;s actual location in memory is known.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">The Core Mechanism: Linker and Loader Teamwork \ud83e\udd1d<\/h2>\n\n\n\n<p>Think of it like moving into a new apartment building. You pack your belongings into boxes, but instead of labeling them with the final apartment number (which you don&#8217;t know yet), you label them with instructions like &#8220;Put this in the kitchen&#8221; or &#8220;Put this 3 meters from the front door.&#8221;<\/p>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\">\n<li><strong>The Linker (The Packer):<\/strong>\u00a0When compiling with flags like\u00a0<code>-fPIE<\/code>\u00a0and\u00a0<code>-pie<\/code>, the linker generates position-independent code.\u00a0For any reference to an absolute address, it doesn&#8217;t write the final address. Instead, it often writes a placeholder (like 0 or an offset) and creates an entry in the relocation table (<code>.rela.dyn<\/code>\u00a0section). This entry is the &#8220;tag&#8221; or &#8220;label&#8221; that says: &#8220;Hey, the 8-byte value at\u00a0<em>this specific offset<\/em>\u00a0in the file needs to be updated at runtime.&#8221;<\/li>\n\n\n\n<li><strong>The Dynamic Loader (The Mover):<\/strong>\u00a0When you run the program, the OS kernel loads the dynamic loader (<code>ld-linux.so.2<\/code>\u00a0on Linux) and the PIE binary into memory at some random address. This random starting point is called the\u00a0<strong>base address<\/strong>. The dynamic loader then reads the relocation table. For each entry, it performs a simple calculation and writes the result back into the memory of the program, effectively &#8220;patching&#8221; it live.<\/li>\n<\/ol>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">How the &#8220;Tagging&#8221; Works: The Relocation Table<\/h2>\n\n\n\n<p>Each entry in the relocation table contains three key pieces of information, effectively &#8220;tagging&#8221; a location for a fix-up.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><code>r_offset<\/code><\/strong>: The location that needs to be patched. This is the virtual address (relative to the start of the binary) of the pointer or instruction operand that holds the placeholder.<\/li>\n\n\n\n<li><strong><code>r_info<\/code><\/strong>: The type of relocation. For internal PIE addresses, the most common type on 64-bit systems is\u00a0<code>$R_X86_64_RELATIVE$<\/code>. This tells the loader\u00a0<em>how<\/em>\u00a0to do the calculation.<\/li>\n\n\n\n<li><strong><code>r_addend<\/code><\/strong>: An initial value to add. For a pointer to a location within the binary, this is the offset of the target from the beginning of the binary.<\/li>\n<\/ul>\n\n\n\n<p>The formula the dynamic loader uses for an&nbsp;<code>$R_X86_64_RELATIVE$<\/code>&nbsp;relocation is simple:<\/p>\n\n\n\n<p>Final&nbsp;Address=Base&nbsp;Address+Addend<\/p>\n\n\n\n<p>The loader calculates this value and writes it to the memory location specified by&nbsp;<code>r_offset<\/code>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">A Concrete Example<\/h2>\n\n\n\n<p>Let&#8217;s look at a simple C program compiled as a PIE.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ file: mypie.c\nint my_global_var = 42;\nint *my_ptr = &amp;my_global_var; \/\/ This requires an absolute address<\/code><\/pre>\n\n\n\n<p>Compile it as a PIE:&nbsp;<code>gcc -fPIE -pie -o mypie mypie.c<\/code><\/p>\n\n\n\n<p>1\u3001<strong>The Code and Placeholder:<\/strong>\u00a0If we inspect the compiled binary&#8217;s data section with\u00a0<code>objdump -s -j .data mypie<\/code>, we&#8217;ll see where\u00a0<code>$my_ptr$<\/code>\u00a0is stored. The linker places a placeholder value there\u2014specifically, the offset of\u00a0<code>$my_global_var$<\/code>.<\/p>\n\n\n\n<p>2\u3001<strong>The Relocation &#8220;Tag&#8221;:<\/strong>\u00a0If we inspect the relocation table with\u00a0<code>readelf -r mypie<\/code>, we&#8217;ll find an entry that looks something like this:<\/p>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\"><\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>Offset             Info             Type               Addend\n0000000000004038   000000000008     R_X86_64_RELATIVE  0000000000004034<\/code><\/pre>\n\n\n\n<p>3\u3001This entry is the &#8220;tag&#8221; for our pointer. It tells the dynamic loader:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Location (<code>Offset<\/code>):<\/strong>\u00a0Go to address\u00a0<code>$0x4038$<\/code>\u00a0within the binary. This is the location of our\u00a0<code>$my_ptr$<\/code>.<\/li>\n\n\n\n<li><strong>How (<code>Type<\/code>):<\/strong>\u00a0Perform a\u00a0<code>$R_X86_64_RELATIVE$<\/code>\u00a0relocation.<\/li>\n\n\n\n<li><strong>What (<code>Addend<\/code>):<\/strong>\u00a0The value to use in the calculation is\u00a0<code>$0x4034$<\/code>. This is the offset of\u00a0<code>$my_global_var$<\/code>\u00a0inside the binary.<\/li>\n<\/ul>\n\n\n\n<p>4\u3001<strong>The Runtime Fix-up:<\/strong>\u00a0Let&#8217;s say the OS loads our binary at the base address\u00a0<strong><code>0x555555554000<\/code><\/strong>.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The dynamic loader reads the relocation entry.<\/li>\n\n\n\n<li>It calculates:\u00a0<code>Base Address + Addend<\/code>\u00a0=>\u00a0<code>$0x555555554000 + 0x4034 = 0x555555558034$<\/code>.<\/li>\n\n\n\n<li>This result,\u00a0<code>$0x555555558034$<\/code>, is the final, correct memory address of\u00a0<code>$my_global_var$<\/code>.<\/li>\n\n\n\n<li>The loader then writes this final address into the location of\u00a0<code>$my_ptr$<\/code>, which is at\u00a0<code>Base Address + Offset<\/code>\u00a0=>\u00a0<code>$0x555555554000 + 0x4038 = 0x555555558038$<\/code>.<\/li>\n<\/ul>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\"><\/ol>\n\n\n\n<p>After this process,&nbsp;<code>$my_ptr$<\/code>&nbsp;holds the correct runtime address, and the program can execute correctly from any base address.<sup><\/sup><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<pre class=\"wp-block-code\"><code>\u201cRelocation section '.rela.dyn' at offset 0x730 contains 12 entries:\n\n  Offset          Info           Type           Sym. Value    Sym. Name + Addend\n\n00000001fd38  000000000403 R_AARCH64_RELATIV                    b20\n\n00000001fd40  000000000403 R_AARCH64_RELATIV                    acc\n\n00000001ffc0  000000000403 R_AARCH64_RELATIV                    b28\n\n000000020008  000000000403 R_AARCH64_RELATIV                    20008\n\n00000001ffb8  000400000401 R_AARCH64_GLOB_DA 0000000000000000 __stack_chk_guard@GLIBC_2.17 + 0\n\n00000001ffc8  000500000401 R_AARCH64_GLOB_DA 0000000000000000 _ZSt4endlIcSt11ch&#91;...]@GLIBCXX_3.4 + 0\n\n00000001ffd0  000600000401 R_AARCH64_GLOB_DA 0000000000000000 __cxa_finalize@GLIBC_2.17 + 0\n\n00000001ffd8  000b00000401 R_AARCH64_GLOB_DA 0000000000000000 _ZSt4cout@GLIBCXX_3.4 + 0\n\n00000001ffe0  000e00000401 R_AARCH64_GLOB_DA 0000000000000000 _ITM_deregisterTM&#91;...] + 0\n\n00000001ffe8  000f00000401 R_AARCH64_GLOB_DA 0000000000000000 _ZSt3cin@GLIBCXX_3.4 + 0\n\n00000001fff0  001000000401 R_AARCH64_GLOB_DA 0000000000000000 __gmon_start__ + 0\n\n00000001fff8  001100000401 R_AARCH64_GLOB_DA 0000000000000000 _ITM_registerTMCl&#91;...] + 0\n\n\n\nRelocation section '.rela.plt' at offset 0x850 contains 8 entries:\n\n  Offset          Info           Type           Sym. Value    Sym. Name + Addend\n\n00000001ff70  000300000402 R_AARCH64_JUMP_SL 0000000000000000 __stack_chk_fail@GLIBC_2.17 + 0\n\n00000001ff78  000600000402 R_AARCH64_JUMP_SL 0000000000000000 __cxa_finalize@GLIBC_2.17 + 0\n\n00000001ff80  000700000402 R_AARCH64_JUMP_SL 0000000000000000 _ZNSirsERi@GLIBCXX_3.4 + 0\n\n00000001ff88  000800000402 R_AARCH64_JUMP_SL 0000000000000000 __libc_start_main@GLIBC_2.34 + 0\n\n00000001ff90  000900000402 R_AARCH64_JUMP_SL 0000000000000000 _ZStlsISt11char_t&#91;...]@GLIBCXX_3.4 + 0\n\n00000001ff98  000a00000402 R_AARCH64_JUMP_SL 0000000000000000 _ZNSolsEPFRSoS_E@GLIBCXX_3.4 + 0\n\n00000001ffa0  000d00000402 R_AARCH64_JUMP_SL 0000000000000000 abort@GLIBC_2.17 + 0\n\n00000001ffa8  001000000402 R_AARCH64_JUMP_SL 0000000000000000 __gmon_start__ + 0\u201d<\/code><\/pre>\n\n\n\n<p>This output is a &#8220;to-do list&#8221; \ud83d\udcdd for your system&#8217;s&nbsp;<strong>dynamic loader<\/strong>&nbsp;(<code>ld-linux.so<\/code>). It&#8217;s from a tool like&nbsp;<code>readelf<\/code>&nbsp;and shows the instructions the loader needs to follow to make a program runnable in memory. This is essential for modern security features like Address Space Layout Randomization (ASLR) and for using shared libraries.<\/p>\n\n\n\n<p>The list is split into two main parts:&nbsp;<code>.rela.dyn<\/code>&nbsp;and&nbsp;<code>.rela.plt<\/code>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">1.&nbsp;<code>.rela.dyn<\/code>&nbsp;(Dynamic Relocations)<\/h3>\n\n\n\n<p>This section handles fix-ups for&nbsp;<strong>data pointers and internal addresses<\/strong>. Think of it as making sure all the program&#8217;s variables and internal references point to the right place once the program is loaded at a random memory address.<\/p>\n\n\n\n<p>You see two main types here:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><code>R_AARCH64_RELATIVE<\/code><\/strong>: This is for\u00a0<strong>internal pointers<\/strong>. These entries tell the loader to calculate an address relative to where the program was loaded.\n<ul class=\"wp-block-list\">\n<li><strong>What it means:<\/strong>\u00a0The\u00a0<code>Addend<\/code>\u00a0column (e.g.,\u00a0<code>b20<\/code>,\u00a0<code>acc<\/code>) is an offset from the start of the program file. The loader takes the program&#8217;s\u00a0<strong>base address<\/strong>\u00a0in memory and adds this offset to get the final, correct memory address. It then writes this final address at the location specified in the\u00a0<code>Offset<\/code>\u00a0column.<\/li>\n\n\n\n<li><strong>Example:<\/strong>\u00a0The first line tells the loader: &#8220;Calculate\u00a0<code>Base Address + 0xb20<\/code>\u00a0and write that result into the memory at\u00a0<code>Base Address + 0x1fd38<\/code>.&#8221;<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong><code>R_AARCH64_GLOB_DAT<\/code><\/strong>: This is for\u00a0<strong>global variables<\/strong>\u00a0from shared libraries (like GLIBC and libstdc++).\n<ul class=\"wp-block-list\">\n<li><strong>What it means:<\/strong>\u00a0This tells the loader to find the address of a variable in a shared library and patch it into your program&#8217;s memory.<\/li>\n\n\n\n<li><strong>Example:<\/strong>\u00a0The entry for\u00a0<code>_ZSt4cout<\/code>\u00a0tells the loader: &#8220;Find the memory address of the standard output stream (<code>std::cout<\/code>) in the C++ library, and write that address into my program&#8217;s memory at\u00a0<code>Base Address + 0x1ffd8<\/code>.&#8221; This allows your program to use\u00a0<code>std::cout<\/code>\u00a0correctly.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">2.&nbsp;<code>.rela.plt<\/code>&nbsp;(Procedure Linkage Table Relocations)<\/h3>\n\n\n\n<p>This section is all about setting up&nbsp;<strong>function calls<\/strong>&nbsp;to shared libraries. It enables a clever optimization called&nbsp;<strong>lazy binding<\/strong>. Instead of finding the address of every single library function at startup (which is slow), the loader sets up a system to find the address the&nbsp;<em>very first time<\/em>&nbsp;a function is called.<\/p>\n\n\n\n<p>This involves two key components: the Procedure Linkage Table (PLT) and the Global Offset Table (GOT).<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><code>R_AARCH64_JUMP_SLOT<\/code><\/strong>: This relocation type is specifically for these function calls.\n<ul class=\"wp-block-list\">\n<li><strong>What it means:<\/strong>\u00a0The\u00a0<code>Offset<\/code>\u00a0points to an entry in the Global Offset Table (GOT). Initially, this entry points to a helper routine in the PLT. When your code calls a function like\u00a0<code>abort<\/code>\u00a0for the first time, it actually jumps to that helper routine. The helper routine then calls the dynamic loader, which looks up the real address of\u00a0<code>abort<\/code>. The loader then &#8220;patches&#8221; the real address into the GOT entry (at the specified\u00a0<code>Offset<\/code>).<\/li>\n\n\n\n<li><strong>The Payoff:<\/strong>\u00a0The\u00a0<em>next<\/em>\u00a0time your code calls\u00a0<code>abort<\/code>, it goes directly to the real function, skipping the loader entirely.<\/li>\n\n\n\n<li><strong>Example:<\/strong>\u00a0The entry for\u00a0<code>abort@GLIBC_2.17<\/code>\u00a0tells the loader: &#8220;Be prepared to find the real address of the\u00a0<code>abort<\/code>\u00a0function. The program has a slot for it at\u00a0<code>Base Address + 0x1ffa0<\/code>.&#8221;<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Summary<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><td>Section<\/td><td>What It&#8217;s For<\/td><td>Analogy<\/td><\/tr><\/thead><tbody><tr><td><strong><code>.rela.dyn<\/code><\/strong><\/td><td>Fixing addresses of&nbsp;<strong>variables<\/strong>&nbsp;(\u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435) and other data, both internal and external.<\/td><td>Writing down the final addresses on a building&#8217;s directory board.<\/td><\/tr><tr><td><strong><code>.rela.plt<\/code><\/strong><\/td><td>Setting up the mechanism for calling&nbsp;<strong>functions<\/strong>&nbsp;(funzioni) from shared libraries.<\/td><td>Creating a speed-dial entry that looks up the number the first time you call.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In a Position-Independent Executable (PIE), absolute addresses aren&#8217;t &#8220;tagged&#8221; directly [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[42],"tags":[30],"class_list":["post-258","post","type-post","status-publish","format-standard","hentry","category-knowledge-base","tag-binary"],"_links":{"self":[{"href":"https:\/\/haco.club\/index.php?rest_route=\/wp\/v2\/posts\/258","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/haco.club\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/haco.club\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/haco.club\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/haco.club\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=258"}],"version-history":[{"count":1,"href":"https:\/\/haco.club\/index.php?rest_route=\/wp\/v2\/posts\/258\/revisions"}],"predecessor-version":[{"id":259,"href":"https:\/\/haco.club\/index.php?rest_route=\/wp\/v2\/posts\/258\/revisions\/259"}],"wp:attachment":[{"href":"https:\/\/haco.club\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=258"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/haco.club\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=258"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/haco.club\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=258"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}