<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>Archive for 2024-01 on chengzhycn&#39;s blog</title>
		<link>https://blog.jinzhi.site/posts/2024-01/</link>
		<description>Recent content in Archive for 2024-01 on chengzhycn&#39;s blog</description>
		<generator>Hugo</generator>
		<language>en-us</language>
		
		
		
		
			<lastBuildDate>Fri, 05 Jan 2024 18:06:28 +0800</lastBuildDate>
		
			<atom:link href="https://blog.jinzhi.site/posts/2024-01/index.xml" rel="self" type="application/rss+xml" />
			<item>
				<title>eBPF 指令集规范</title>
				<link>https://blog.jinzhi.site/posts/2024-01/ebpf-%E6%8C%87%E4%BB%A4%E9%9B%86%E8%A7%84%E8%8C%83/</link>
				<pubDate>Fri, 05 Jan 2024 18:06:28 +0800</pubDate>
				<guid>https://blog.jinzhi.site/posts/2024-01/ebpf-%E6%8C%87%E4%BB%A4%E9%9B%86%E8%A7%84%E8%8C%83/</guid>
				<description>&lt;p&gt;&lt;a href=&#34;https://docs.kernel.org/bpf/standardization/instruction-set.html&#34;&gt;1 BPF Instruction Set Specification, v1.0 — The Linux Kernel documentation&lt;/a&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;寄存器和调用约定&#34;&gt;寄存器和调用约定&lt;/h2&gt;&#xA;&lt;p&gt;eBPF有10个通用寄存器和一个只读的帧指针寄存器，所有的寄存器都是64bits位长。&lt;/p&gt;&#xA;&lt;p&gt;eBPF的调用约定如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;R0:&lt;/strong&gt; 函数调用的返回值和eBPF程序的退出值&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;R1 - R5:&lt;/strong&gt; 函数调用的参数&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;R6 - R9:&lt;/strong&gt; callee saved registers，由函数调用负责保存到栈上&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;R10:&lt;/strong&gt; 只读的帧指针，用于访问栈&#xA;R0 - R5是临时寄存器，eBPF程序在函数调用时如需使用需要将它们保存/填充。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;指令编码&#34;&gt;指令编码&lt;/h2&gt;&#xA;&lt;p&gt;eBPF使用64bit指令，编码如下：&lt;/p&gt;&#xA;&lt;table&gt;&#xA;&#x9;&lt;thead&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;&lt;strong&gt;32位（最高有效位）&lt;/strong&gt;&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;&lt;strong&gt;16位&lt;/strong&gt;&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;&lt;strong&gt;4位&lt;/strong&gt;&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;&lt;strong&gt;4位&lt;/strong&gt;&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;&lt;strong&gt;8位（最低有效位）&lt;/strong&gt;&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&lt;/thead&gt;&#xA;&#x9;&lt;tbody&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;immediate&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;offset&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;source register&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;dest register&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;opcode&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;imm: 有符号整型立即数&lt;/li&gt;&#xA;&lt;li&gt;offset: 有符号整型数，用于指针算术&lt;/li&gt;&#xA;&lt;li&gt;src_reg: 除开特殊指令的编码外（如64位立即数指令）指的是源寄存器(R0 - R10)&lt;/li&gt;&#xA;&lt;li&gt;dst_reg: 目标寄存器(R0 - R10)&lt;/li&gt;&#xA;&lt;li&gt;opcode: 操作码&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;绝大多数指令不会使用所有的字段。没有使用的字段应当被置0。多字节的字段（如imm和offset）在大端BPF中以大端字节序存储，小端BPF中以小端字节序存储。&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;opcode                  offset imm          assembly&#xA;       src_reg dst_reg&#xA;07     0       1        00 00  44 33 22 11  r1 += 0x11223344 // little&#xA;       dst_reg src_reg&#xA;07     1       0        00 00  11 22 33 44  r1 += 0x11223344 // big&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;除了这些基本指令编码外，eBPF还有一种宽指令编码，在基本指令之后使用第2个64位立即数做扩展。第2个立即数包括一个伪指令，和基本指令的格式一样，不过所有的字段（除了imm）都置为0。它的imm作为整个宽指令中的imm64值的高32位：&lt;/p&gt;</description>
			</item>
			<item>
				<title>eBPF 全局变量的实现</title>
				<link>https://blog.jinzhi.site/posts/2024-01/ebpf-%E5%85%A8%E5%B1%80%E5%8F%98%E9%87%8F%E7%9A%84%E5%AE%9E%E7%8E%B0/</link>
				<pubDate>Tue, 02 Jan 2024 19:46:28 +0800</pubDate>
				<guid>https://blog.jinzhi.site/posts/2024-01/ebpf-%E5%85%A8%E5%B1%80%E5%8F%98%E9%87%8F%E7%9A%84%E5%AE%9E%E7%8E%B0/</guid>
				<description>&lt;p&gt;Linux内核在v5.2支持了eBPF全局变量（见&lt;a href=&#34;https://www.yuque.com/chengzhycn/hx665b/cmbgkdheaf0wyqht#vVcxE&#34;&gt;v5.2&lt;/a&gt;）。&lt;/p&gt;&#xA;&lt;p&gt;全局变量会被Clang编译器放入&lt;code&gt;.bss&lt;/code&gt;, &lt;code&gt;.data&lt;/code&gt;, &lt;code&gt;.rodata&lt;/code&gt; sections。那么支持全局变量即如何把这些sections中的数据加载进内核，并且在relocation时，给访问这些变量的指令正确的地址。&lt;/p&gt;&#xA;&lt;h2 id=&#34;早期-workaround&#34;&gt;早期 workaround&lt;/h2&gt;&#xA;&lt;p&gt;关于 eBPF 静态变量支持的讨论在&lt;a href=&#34;https://lpc.events/event/2/contributions/115/&#34;&gt;Linux Plumbers Conference 2018&lt;/a&gt; 由Cilium提出。早期的 workaround 如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;linux/bpf.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;typedef&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__u32&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;typedef&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#ifndef __section&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;# define __section(NAME)&#x9;&#x9;&#x9;&#x9;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;&#x9;__attribute__((section(NAME), used))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#endif&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#ifndef __fetch&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;# define __fetch(x) (__u32)(__u64)(&amp;amp;(x))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#endif&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;__u32&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;foo&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;42&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &#x9;&#x9;&#x9;&lt;span class=&#34;c1&#34;&gt;// .data section&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// __u32 foo;   &#x9;&#x9;&#x9;// .bss section&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// const __u32 foo = 42; &#x9;// .rodata section&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;__main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__sk_buff&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;skb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;skb&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mark&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;__fetch&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;foo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__license&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;__section&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;license&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;编译后，foo变量存储在&lt;code&gt;.data&lt;/code&gt; section内。&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# llvm-readelf -S test.o&#xA;There are 8 section headers, starting at offset 0x148:&#xA;&#xA;Section Headers:&#xA;  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al&#xA;  [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0&#xA;  [ 1] .strtab           STRTAB          0000000000000000 0000fa 00004b 00      0   0  1&#xA;  [ 2] .text             PROGBITS        0000000000000000 000040 000028 00  AX  0   0  8&#xA;  [ 3] .rel.text         REL             0000000000000000 0000e8 000010 10      7   2  8&#xA;  [ 4] .data             PROGBITS        0000000000000000 000068 000004 00  WA  0   0  4&#xA;  [ 5] license           PROGBITS        0000000000000000 00006c 000001 00  WA  0   0  1&#xA;  [ 6] .llvm_addrsig     LLVM_ADDRSIG    0000000000000000 0000f8 000002 00   E  7   0  1&#xA;  [ 7] .symtab           SYMTAB          0000000000000000 000070 000078 18      1   2  8&#xA;Key to Flags:&#xA;  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),&#xA;  L (link order), O (extra OS processing required), G (group), T (TLS),&#xA;  C (compressed), x (unknown), o (OS specific), E (exclude),&#xA;  p (processor specific)&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;.rel.text&lt;/code&gt; section中也存在foo变量的relocation信息：&lt;/p&gt;</description>
			</item>
	</channel>
</rss>
