{"componentChunkName":"component---src-templates-blog-post-js","path":"/per_cpu_var_and_relochide/","result":{"data":{"site":{"siteMetadata":{"title":"/dev/yukarinoki"}},"markdownRemark":{"id":"6a4c928b-bc70-5d3c-8cf9-28778658f649","excerpt":"Per cpu variable linux kernelには、per cpu variableという機構があります。(Per-CPU Variablesとも書かれる。) per cpu variableはその名前の通りCPU Coreごとの変数です。\ncore…","html":"<h1 id=\"per-cpu-variable\" style=\"position:relative;\"><a href=\"#per-cpu-variable\" aria-label=\"per cpu variable permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Per cpu variable</h1>\n<p>linux kernelには、per cpu variableという機構があります。(Per-CPU Variablesとも書かれる。)<br>\nper cpu variableはその名前の通りCPU Coreごとの変数です。\ncoreごとの変数を用いないとキャッシュが汚れてしまうのでパフォーマンスが大幅に低下します。\nこの点から、linux kernelでは多くのper cpu variableが使われています。  </p>\n<p>per cpu variableが用いられている例としては、バディシステムにおけるper_cpu_pagesなどが挙げられます。</p>\n<p>Per-CPU Variablesの概要については、Linux Device Drivers, Third Edition Chapter8 p228 (<a href=\"https://lwn.net/Kernel/LDD3/\">https://lwn.net/Kernel/LDD3/</a>) にも記述があります。参考にしてください。</p>\n<p><strong>注意: プログラム内のコードは解説のための疑似コードであり、動きません</strong></p>\n<h1 id=\"per-cpu-variableの配置\" style=\"position:relative;\"><a href=\"#per-cpu-variable%E3%81%AE%E9%85%8D%E7%BD%AE\" aria-label=\"per cpu variableの配置 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Per cpu variableの配置</h1>\n<p>linuxはC, asm, ldsで書かれています。ちなみにCのstandard内だけで書くことはできません。このldsとはリンカスクリプトです、linuxはvmlinuxという形に実行形式をまとめますが、そのときのdataやtextなどのセクションの位置を記述しています。\nper cpu variableはldsによって配置されアドレスは固定されています。<br>\n/arch/x86/kernel/vmlinux.lds.S<br>\n/include/asm-generic/vmlinux.lds.h<br>\n<a href=\"https://elixir.bootlin.com/linux/v5.9.4/source/include/asm-generic/sections.h#L42\">https://elixir.bootlin.com/linux/v5.9.4/source/include/asm-generic/sections.h#L42</a>   </p>\n<div class=\"gatsby-code-title\">/include/asm-generic/sections.h</div>\n<div class=\"gatsby-highlight\" data-language=\"clike\"><pre style=\"counter-reset: linenumber NaN\" class=\"language-clike line-numbers\"><code class=\"language-clike\">extern char __per_cpu_load<span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span> __per_cpu_start<span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span> __per_cpu_end<span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span></code><span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"white-space: normal; width: auto; left: 0;\"><span></span></span></pre></div>\n<p>こうして配置されたメモリ、data.per_cpu_area セクションがkernel起動時に初期化されます。<br>\n<a href=\"https://elixir.bootlin.com/linux/latest/source/arch/x86/kernel/setup_percpu.c#L168\">https://elixir.bootlin.com/linux/latest/source/arch/x86/kernel/setup_percpu.c#L168</a>  </p>\n<div class=\"gatsby-code-title\">/arch/x86/kernel/setup_percpu.c</div>\n<div class=\"gatsby-highlight\" data-language=\"c\"><pre style=\"counter-reset: linenumber NaN\" class=\"language-c line-numbers\"><code class=\"language-c\"><span class=\"token keyword\">void</span> __init <span class=\"token function\">setup_per_cpu_areas</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">void</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n<span class=\"token operator\">~</span><span class=\"token operator\">~</span>\n<span class=\"token function\">for_each_possible_cpu</span><span class=\"token punctuation\">(</span>cpu<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n\t\t<span class=\"token function\">per_cpu_offset</span><span class=\"token punctuation\">(</span>cpu<span class=\"token punctuation\">)</span> <span class=\"token operator\">=</span> delta <span class=\"token operator\">+</span> pcpu_unit_offsets<span class=\"token punctuation\">[</span>cpu<span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span>\n\t\t<span class=\"token function\">per_cpu</span><span class=\"token punctuation\">(</span>this_cpu_off<span class=\"token punctuation\">,</span> cpu<span class=\"token punctuation\">)</span> <span class=\"token operator\">=</span> <span class=\"token function\">per_cpu_offset</span><span class=\"token punctuation\">(</span>cpu<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\t\t<span class=\"token function\">per_cpu</span><span class=\"token punctuation\">(</span>cpu_number<span class=\"token punctuation\">,</span> cpu<span class=\"token punctuation\">)</span> <span class=\"token operator\">=</span> cpu<span class=\"token punctuation\">;</span>\n\t\t<span class=\"token function\">setup_percpu_segment</span><span class=\"token punctuation\">(</span>cpu<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\t\t<span class=\"token function\">setup_stack_canary_segment</span><span class=\"token punctuation\">(</span>cpu<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\t\t<span class=\"token comment\">/*\n\t\t * Copy data used in early init routines from the\n\t\t * initial arrays to the per cpu data areas.  These\n\t\t * arrays then become expendable and the *_early_ptr's\n\t\t * are zeroed indicating that the static arrays are\n\t\t * gone.\n\t\t */</span>\n<span class=\"token macro property\">#<span class=\"token directive keyword\">ifdef</span> CONFIG_X86_LOCAL_APIC</span>\n\t\t<span class=\"token function\">per_cpu</span><span class=\"token punctuation\">(</span>x86_cpu_to_apicid<span class=\"token punctuation\">,</span> cpu<span class=\"token punctuation\">)</span> <span class=\"token operator\">=</span>\n\t\t\t<span class=\"token function\">early_per_cpu_map</span><span class=\"token punctuation\">(</span>x86_cpu_to_apicid<span class=\"token punctuation\">,</span> cpu<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\t\t<span class=\"token function\">per_cpu</span><span class=\"token punctuation\">(</span>x86_bios_cpu_apicid<span class=\"token punctuation\">,</span> cpu<span class=\"token punctuation\">)</span> <span class=\"token operator\">=</span>\n\t\t\t<span class=\"token function\">early_per_cpu_map</span><span class=\"token punctuation\">(</span>x86_bios_cpu_apicid<span class=\"token punctuation\">,</span> cpu<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\t\t<span class=\"token function\">per_cpu</span><span class=\"token punctuation\">(</span>x86_cpu_to_acpiid<span class=\"token punctuation\">,</span> cpu<span class=\"token punctuation\">)</span> <span class=\"token operator\">=</span>\n\t\t\t<span class=\"token function\">early_per_cpu_map</span><span class=\"token punctuation\">(</span>x86_cpu_to_acpiid<span class=\"token punctuation\">,</span> cpu<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token macro property\">#<span class=\"token directive keyword\">endif</span></span>\n<span class=\"token operator\">~</span><span class=\"token operator\">~</span></code><span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"white-space: normal; width: auto; left: 0;\"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div>\n<h2 id=\"per-cpu-variablesの構造\" style=\"position:relative;\"><a href=\"#per-cpu-variables%E3%81%AE%E6%A7%8B%E9%80%A0\" aria-label=\"per cpu variablesの構造 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Per cpu variablesの構造</h2>\n<p>per cpu variableは以下のような構造になっています。このCPU 0, CPU 1 という領域にいくつものオブジェクトが入っています。同じ変数(同名だがCPUごとに異なる変数の意味)なら各CPUの領域のstartからのoffsetは等しくなっています。<br>\nこのため、</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre style=\"counter-reset: linenumber NaN\" class=\"language-text line-numbers\"><code class=\"language-text\">（CPUiの構造体Aのptr）= (CPU0の構造体Aのptr) + (i-1)×(各CPU領域のサイズ) </code><span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"white-space: normal; width: auto; left: 0;\"><span></span></span></pre></div>\n<p>でそれぞれのCPUの変数アドレスを計算することができます。  </p>\n<p>このような実装はChristophさんの考案です。<br>\n参考: <a href=\"https://lwn.net/Articles/258238/\">https://lwn.net/Articles/258238/</a></p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 590px; \"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/6f0319ac338fb9750736bbd2ff28c02f/27524/per_cpu_var.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 83.1081081081081%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAARCAYAAADdRIy+AAAACXBIWXMAABYlAAAWJQFJUiTwAAACaUlEQVQ4y21T2ZKiQBD0/79o98WXHY/RWa+NUfACURFU8ELxgtzKdloltCMqummqqyqzsnJ4s9brNdrtNmzbhjUcwpK9Oxg8rNvNWK/XU/5BECC33+8RhiFWq5Xa+d1qtdBsNrFYLGCPRnAkSLxcIprPsZe7fRQpP1ok5+PxCNd10e/3keOjoVTRaDTUxWQyQblcRq1Ww2w6hSH/Br9+A+Uq8FUHPorA4fCCisEty0LuGaZenuepiu8rTZEuAyAI6ai+9WIRhGwYxq3CJEnUD1Z6vV7VmZkKhQL6AtUUx541RFsq7WjrdNARzriXSiWFKJ/Pq8C59CcbOSCpcRwrR2Y7CDRPeHMME5hLwpmHxJ8jkcSJvNPFcG232xtkHZAwCft8PqvOjaQZ18sF4W4H988HUP0LNFtAqSIcxi8c7sQvE3ApXdQZ2Rga/zHBRaqOPR+x76tuEwXtdDopNdAomwzk54DUH3lhRjoN5NsQM5VZME3zbvV6XQUsFouvHM6FL+qK2Silk+jLl2Y539+AcAd3Jtz472bhIRsd0Bc4DMYqGYwJuCKBFVS/fjj8B3yKHuPjPZBGxabwXQaylo3jOKoxJJp63EizAmlaSBMUnCgqgk0kVEqsUqmoN/eAzzpkhzkprNKR83g2g+1OYcvkqF3uyDON8iJUPWmZgKyS2qMO6XwR2SykklGjeeOOHE7dtxzyXYZDckFiGUTPdCp35HBdkxkuft5mmfvxwSH99egqDm+jmmayZTgUvtbRDsvNBgG55C53REN+OXrkkTKjjO4VctdnLYHxeKyCk0e1q7PzOItpLlkdxf4fBxv7G/peOt4AAAAASUVORK5CYII='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"pcv\"\n        title=\"pcv\"\n        src=\"/static/6f0319ac338fb9750736bbd2ff28c02f/fcda8/per_cpu_var.png\"\n        srcset=\"/static/6f0319ac338fb9750736bbd2ff28c02f/12f09/per_cpu_var.png 148w,\n/static/6f0319ac338fb9750736bbd2ff28c02f/e4a3f/per_cpu_var.png 295w,\n/static/6f0319ac338fb9750736bbd2ff28c02f/fcda8/per_cpu_var.png 590w,\n/static/6f0319ac338fb9750736bbd2ff28c02f/27524/per_cpu_var.png 646w\"\n        sizes=\"(max-width: 590px) 100vw, 590px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n  </a>\n    </span></p>\n<h1 id=\"reloc_hide\" style=\"position:relative;\"><a href=\"#reloc_hide\" aria-label=\"reloc_hide permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>RELOC_HIDE()</h1>\n<h2 id=\"offset加算の問題点\" style=\"position:relative;\"><a href=\"#offset%E5%8A%A0%E7%AE%97%E3%81%AE%E5%95%8F%E9%A1%8C%E7%82%B9\" aria-label=\"offset加算の問題点 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>offset加算の問題点</h2>\n<p>先ほど、\n（CPUiの構造体Aのポインタ）= (CPU0の構造体Aのポインタ) + (i-1)×(各CPU領域のサイズ)\nで当該CPUのper cpu variableのポインタを取得できると書きましたが、ここには一つの問題があります。<br>\nそれは、<strong>このような操作はC standardを逸脱しておりundefined behaviorに該当する</strong>ものだということです。<br>\nでは、なにがUB(Undefined behavior)なのでしょうか？  </p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre style=\"counter-reset: linenumber NaN\" class=\"language-text line-numbers\"><code class=\"language-text\">(i-1)×(各CPU領域のサイズ) = offset  \n（CPUiの構造体Aのポインタ）= ptri  \n(CPU0の構造体Aのポインタ) = ptr0  </code><span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"white-space: normal; width: auto; left: 0;\"><span></span><span></span><span></span></span></pre></div>\n<p>とします。<br>\nここで、上の操作は ptri = ptr0 + offsetなわけですが、<strong>このoffsetの加算は確実にptr0の指し示している構造体のサイズを超えています。 この構造体の範囲を超えるptrの加算がUBになります。</strong></p>\n<p>例を示します。</p>\n<div class=\"gatsby-code-title\">example1.c</div>\n<div class=\"gatsby-highlight\" data-language=\"c\"><pre style=\"counter-reset: linenumber NaN\" class=\"language-c line-numbers\"><code class=\"language-c\"><span class=\"token keyword\">struct</span> <span class=\"token class-name\">person</span> <span class=\"token punctuation\">{</span>            \n    <span class=\"token keyword\">char</span> name<span class=\"token punctuation\">[</span><span class=\"token number\">20</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span>        \n    <span class=\"token keyword\">int</span> age<span class=\"token punctuation\">;</span>                \n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">int</span> <span class=\"token function\">main</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">struct</span> <span class=\"token class-name\">person</span> A<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"Nanoha\"</span><span class=\"token punctuation\">,</span> <span class=\"token number\">8</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> B<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"Fate\"</span><span class=\"token punctuation\">,</span> <span class=\"token number\">9</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">char</span><span class=\"token operator\">*</span> ptr <span class=\"token operator\">=</span> <span class=\"token operator\">&amp;</span>A<span class=\"token punctuation\">.</span>name<span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">int</span><span class=\"token operator\">*</span> age_ptr <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">int</span> <span class=\"token operator\">*</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">(</span>ptr <span class=\"token operator\">+</span> <span class=\"token number\">20</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// in C standard</span>\n  <span class=\"token keyword\">char</span><span class=\"token operator\">*</span> B_name_ptr <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">int</span> <span class=\"token operator\">*</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">(</span>ptr <span class=\"token operator\">+</span> <span class=\"token number\">24</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// UB!</span>\n  \n  <span class=\"token function\">printf</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"vars: %d, %s\\n\"</span><span class=\"token punctuation\">,</span> <span class=\"token operator\">*</span>age_ptr<span class=\"token punctuation\">,</span> B_name_ptr<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// vars: 8, Fate</span>\n<span class=\"token punctuation\">}</span></code><span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"white-space: normal; width: auto; left: 0;\"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div>\n<p>構造体の中から中へoffsetを加算してptrを計算するのはCstandardに含まれますが、構造体の<strong>外に</strong>offsetを加算してptrを計算するのはUBです。</p>\n<p>ただ、上のコードのように動く場合もあります。しかし、UBは「コンパイラがどう処理しても構わない」ということなので、UBを発見次第、「なのはちゃんの全力全開！」と出力してコンパイルを停止するという動作もコンパイラの裁量の範囲内になります。（ほんとか？）  </p>\n<p>具体的には、</p>\n<div class=\"gatsby-highlight\" data-language=\"c\"><pre style=\"counter-reset: linenumber NaN\" class=\"language-c line-numbers\"><code class=\"language-c\"><span class=\"token keyword\">struct</span> <span class=\"token class-name\">person</span> <span class=\"token punctuation\">{</span>            \n    <span class=\"token keyword\">char</span> name<span class=\"token punctuation\">[</span><span class=\"token number\">20</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span>        \n    <span class=\"token keyword\">int</span> age<span class=\"token punctuation\">;</span>                \n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">int</span> <span class=\"token function\">main</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">struct</span> <span class=\"token class-name\">person</span> A<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"Nanoha\"</span><span class=\"token punctuation\">,</span> <span class=\"token number\">8</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> B<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"Fate\"</span><span class=\"token punctuation\">,</span> <span class=\"token number\">9</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">struct</span> <span class=\"token class-name\">person</span> <span class=\"token operator\">*</span>ptr <span class=\"token operator\">=</span> <span class=\"token operator\">&amp;</span>A<span class=\"token punctuation\">;</span> \n  <span class=\"token keyword\">if</span><span class=\"token punctuation\">(</span>ptr <span class=\"token operator\">+</span> offset <span class=\"token operator\">></span> <span class=\"token number\">0</span> <span class=\"token operator\">&amp;&amp;</span> ptr <span class=\"token operator\">+</span> offset <span class=\"token operator\">&lt;</span> ptr <span class=\"token operator\">+</span> <span class=\"token keyword\">sizeof</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">struct</span> <span class=\"token class-name\">person</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">{</span>\n    <span class=\"token operator\">~</span><span class=\"token operator\">~</span><span class=\"token operator\">~</span><span class=\"token operator\">~</span><span class=\"token operator\">~</span>\n  <span class=\"token punctuation\">}</span>\n  <span class=\"token comment\">/*\n  * ptr + offset > 0 &amp;&amp; ptr + offset &lt; ptr + sizeof(struct person)\n  * は最適化によって、ptr + offset > 0に変換される可能性がある。\n  * ptrに何を足してもその構造体のサイズを超えることがないと仮定されるため。\n  */</span>\n<span class=\"token punctuation\">}</span></code><span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"white-space: normal; width: auto; left: 0;\"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div>\n<p>という可能性があります。</p>\n<h2 id=\"reloc_hide-1\" style=\"position:relative;\"><a href=\"#reloc_hide-1\" aria-label=\"reloc_hide 1 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>RELOC_HIDE</h2>\n<p>以上の問題を解決するためにRELOC_HIDE()があります。\n<a href=\"https://elixir.bootlin.com/linux/v4.18/source/include/linux/compiler-gcc.h#L50\">https://elixir.bootlin.com/linux/v4.18/source/include/linux/compiler-gcc.h#L50</a></p>\n<div class=\"gatsby-code-title\">include/linux/compiler-gcc.h</div>\n<div class=\"gatsby-highlight\" data-language=\"c\"><pre style=\"counter-reset: linenumber NaN\" class=\"language-c line-numbers\"><code class=\"language-c\"><span class=\"token macro property\">#<span class=\"token directive keyword\">define</span> RELOC_HIDE(ptr, off)\t\t\t\t\t\t\\\n({\t\t\t\t\t\t\t\t\t\\\n\tunsigned long __ptr;\t\t\t\t\t\t\\\n\t__asm__ (\"\" : \"=r\"(__ptr) : \"0\"(ptr));\t\t\t\t\\\n\t(typeof(ptr)) (__ptr + (off));\t\t\t\t\t\\\n})</span></code><span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"white-space: normal; width: auto; left: 0;\"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div>\n<h2 id=\"拡張アセンブリ\" style=\"position:relative;\"><a href=\"#%E6%8B%A1%E5%BC%B5%E3%82%A2%E3%82%BB%E3%83%B3%E3%83%96%E3%83%AA\" aria-label=\"拡張アセンブリ permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>拡張アセンブリ</h2>\n<p>そもそも、この拡張インラインアセンブリが読めないかもしれないので解説します。<br>\n分かりやすい解説: <a href=\"http://caspar.hazymoon.jp/OpenBSD/annex/gcc_inline_asm.html\">http://caspar.hazymoon.jp/OpenBSD/annex/gcc_inline_asm.html</a>　</p>\n<div class=\"gatsby-highlight\" data-language=\"c\"><pre style=\"counter-reset: linenumber NaN\" class=\"language-c line-numbers\"><code class=\"language-c\"><span class=\"token function\">__asm__</span> <span class=\"token punctuation\">(</span>\n          <span class=\"token string\">\"\"</span> <span class=\"token operator\">:</span>          <span class=\"token comment\">// asm template, asmのコード</span>\n          <span class=\"token string\">\"=r\"</span><span class=\"token punctuation\">(</span>__ptr<span class=\"token punctuation\">)</span> <span class=\"token operator\">:</span> <span class=\"token comment\">// 出力レジスタ(カッコ内は対応する変数)</span>\n          <span class=\"token string\">\"0\"</span><span class=\"token punctuation\">(</span>ptr<span class=\"token punctuation\">)</span>      <span class=\"token comment\">// 入力レジスタ(カッコ内は対応する変数)</span>\n        <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code><span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"white-space: normal; width: auto; left: 0;\"><span></span><span></span><span></span><span></span><span></span></span></pre></div>\n<p>をそれぞれ意味しています。(それぞれの間を:でつないでいる。)\nアセンブリはレジスタを陽に扱いますが、C言語ではレジスタは扱われません。そのため、単純にアセンブラを書くと、その瞬間レジスタにどの変数が入っているかによって、結果が変わってしまいます。その瞬間のレジスタがどの変数に対応しているかは簡単にはわかりません。この問題に対応するために拡張アセンブリ構文があります。</p>\n<p><strong>拡張アセンブリ</strong> </p>\n<ol>\n<li>入力レジスタに基づいて、変数をレジスタに導入</li>\n<li>asm templeteに記述されたasm code</li>\n<li>出力レジスタに基づいて、変数をレジスタに導入\nというアセンブリコードを生成してくれます。</li>\n</ol>\n<p><strong>通常のインラインアセンブリ</strong></p>\n<ol>\n<li>asm templeteに記述されたasm code\nだけをやってくれます。</li>\n</ol>\n<p>出力入力レジスタに制約というアノテーションをつけることもでき、RELOC_HIDE()の場合では</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre style=\"counter-reset: linenumber NaN\" class=\"language-text line-numbers\"><code class=\"language-text\">&quot;=r&quot; = は読み込み専用、rはどのレジスタでもいいという意味\n&quot;0&quot;  0 は出力レジスタの0番目にこの変数を入れる</code><span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"white-space: normal; width: auto; left: 0;\"><span></span><span></span></span></pre></div>\n<p>を意味しています。</p>\n<h2 id=\"reloc-hideがやっていること\" style=\"position:relative;\"><a href=\"#reloc-hide%E3%81%8C%E3%82%84%E3%81%A3%E3%81%A6%E3%81%84%E3%82%8B%E3%81%93%E3%81%A8\" aria-label=\"reloc hideがやっていること permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>RELOC HIDEがやっていること</h2>\n<div class=\"gatsby-code-title\">include/linux/compiler-gcc.h</div>\n<div class=\"gatsby-highlight\" data-language=\"c\"><pre style=\"counter-reset: linenumber NaN\" class=\"language-c line-numbers\"><code class=\"language-c\"><span class=\"token macro property\">#<span class=\"token directive keyword\">define</span> RELOC_HIDE(ptr, off)\t\t\t\t\t\t\\\n({\t\t\t\t\t\t\t\t\t\\\n\tunsigned long __ptr;\t\t\t\t\t\t\\\n\t__asm__ (\"\" : \"=r\"(__ptr) : \"0\"(ptr));\t\t\t\t\\\n\t(typeof(ptr)) (__ptr + (off));\t\t\t\t\t\\\n})</span></code><span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"white-space: normal; width: auto; left: 0;\"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div>\n<p>この拡張アセンブリはasm templeteが空文字列になっています。つまり、asmの操作は何もしないで、変数をレジスタに入れて、レジスタから変数に出すということだけを行っています。</p>\n<ol>\n<li>入力レジスタに基づいて、変数をレジスタに導入</li>\n<li>（asm templeteに記述されたasm code）&#x3C;-これがない</li>\n<li>出力レジスタに基づいて、変数をレジスタに導入</li>\n</ol>\n<p>そして、どのように変数をレジスタに出し入れしているかというと、</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre style=\"counter-reset: linenumber NaN\" class=\"language-text line-numbers\"><code class=\"language-text\">ptr -&gt; register -&gt; __ptr 　// &quot;0&quot;によってptrは__ptrと同じ変数に対応付けられる</code><span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"white-space: normal; width: auto; left: 0;\"><span></span></span></pre></div>\n<p>ということは</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre style=\"counter-reset: linenumber NaN\" class=\"language-text line-numbers\"><code class=\"language-text\">__ptr = ptr </code><span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"white-space: normal; width: auto; left: 0;\"><span></span></span></pre></div>\n<p>をやっているだけなんですね。\nあとは、__にoffsetを足して返すだけ。</p>\n<p>これは一見なんの意味もなさそうですが、<br>\n<strong>アセンブリを介すことによってコンパイラのoptimizerに__ptrがptrと同じ構造体のポインタであることを隠すことができます。</strong> それによって、コンパイラはどんなサイズの構造体のポインタかわからず、offsetを足しても構造体のサイズ内なのかもしれないと考えてコード除去をすることができなくなります。</p>\n<p>以上が RELOC_HIDE()の意味になります。</p>\n<h1 id=\"最後に\" style=\"position:relative;\"><a href=\"#%E6%9C%80%E5%BE%8C%E3%81%AB\" aria-label=\"最後に permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>最後に</h1>\n<p>日本語で解説されているものがなかったので書きました。このptrの加算はアップキャストと似たようなもやっと感がありますね。こういうコードがほとんどのハードウェアの上でちゃんと動作するのはすごいことだと思いました。</p>","tableOfContents":"<ul>\n<li><a href=\"/per_cpu_var_and_relochide/#per-cpu-variable\">Per cpu variable</a></li>\n<li>\n<p><a href=\"/per_cpu_var_and_relochide/#per-cpu-variable%E3%81%AE%E9%85%8D%E7%BD%AE\">Per cpu variableの配置</a></p>\n<ul>\n<li><a href=\"/per_cpu_var_and_relochide/#per-cpu-variables%E3%81%AE%E6%A7%8B%E9%80%A0\">Per cpu variablesの構造</a></li>\n</ul>\n</li>\n<li>\n<p><a href=\"/per_cpu_var_and_relochide/#reloc_hide\">RELOC_HIDE()</a></p>\n<ul>\n<li><a href=\"/per_cpu_var_and_relochide/#offset%E5%8A%A0%E7%AE%97%E3%81%AE%E5%95%8F%E9%A1%8C%E7%82%B9\">offset加算の問題点</a></li>\n<li><a href=\"/per_cpu_var_and_relochide/#reloc_hide-1\">RELOC_HIDE</a></li>\n<li><a href=\"/per_cpu_var_and_relochide/#%E6%8B%A1%E5%BC%B5%E3%82%A2%E3%82%BB%E3%83%B3%E3%83%96%E3%83%AA\">拡張アセンブリ</a></li>\n<li><a href=\"/per_cpu_var_and_relochide/#reloc-hide%E3%81%8C%E3%82%84%E3%81%A3%E3%81%A6%E3%81%84%E3%82%8B%E3%81%93%E3%81%A8\">RELOC HIDEがやっていること</a></li>\n</ul>\n</li>\n<li><a href=\"/per_cpu_var_and_relochide/#%E6%9C%80%E5%BE%8C%E3%81%AB\">最後に</a></li>\n</ul>","frontmatter":{"title":"per_cpu_variableとRELOC_HIDE()","date":"November 06, 2020","description":"per_cpu_variableとRELOC_HIDE()の解説"}}},"pageContext":{"slug":"/per_cpu_var_and_relochide/","previous":{"fields":{"slug":"/readings_Nov20/"},"frontmatter":{"title":"Nov 2020 読んだもの、やったこと"}},"next":{"fields":{"slug":"/making_toc/"},"frontmatter":{"title":"gatsby-blogにtable of contentを付ける"}}}}}