<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh">
    <title>bigfish的网络博客 - FFI</title>
    <subtitle>记录技术和生活</subtitle>
    <link rel="self" type="application/atom+xml" href="https://blog.bigfisharc.cn/tags/ffi/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://blog.bigfisharc.cn"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-10-17T23:05:00+08:00</updated>
    <id>https://blog.bigfisharc.cn/tags/ffi/atom.xml</id>
    <entry xml:lang="zh">
        <title>Rust FFI 和 ABI 是什么关系？从一个字段写错的结构体说起</title>
        <published>2026-10-17T23:05:00+08:00</published>
        <updated>2026-10-17T23:05:00+08:00</updated>
        
        <author>
          <name>bigfish</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.bigfisharc.cn/blog/20261017-2305-rust-ffihe-abishi-shen-me-guan-xi/"/>
        <id>https://blog.bigfisharc.cn/blog/20261017-2305-rust-ffihe-abishi-shen-me-guan-xi/</id>
        
        <summary type="html">&lt;p&gt;先看一个能正常跑起来、但结果是错的例子。&lt;/p&gt;
&lt;p&gt;插件侧编译成 &lt;code&gt;cdylib&lt;/code&gt;，导出两个函数。&lt;code&gt;cdylib&lt;/code&gt; 是供其他代码加载、调用的动态库产物，不要求调用方也是 Rust：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;repr&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;C&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-8&quot;&gt;pub&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-8&quot;&gt; struct&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; Point&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-8&quot;&gt;    pub&lt;/span&gt;&lt;span class=&quot;z-l-3&quot;&gt; x&lt;/span&gt;&lt;span class=&quot;z-d-8&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; i32&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-8&quot;&gt;    pub&lt;/span&gt;&lt;span class=&quot;z-l-3&quot;&gt; y&lt;/span&gt;&lt;span class=&quot;z-d-8&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; i32&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;no_mangle&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-8&quot;&gt;pub&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-8&quot;&gt; extern&lt;/span&gt;&lt;span class=&quot;z-l-12 z-d-5&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-12 z-d-5&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;z-l-12 z-d-5&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-8&quot;&gt; fn&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-6&quot;&gt; point_new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-3&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;z-d-8&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; i32&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-3&quot;&gt; y&lt;/span&gt;&lt;span class=&quot;z-d-8&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; i32&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-d-8&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; Point&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    Point&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;span class=&quot;z-l-3&quot;&gt; x&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-3&quot;&gt; y&lt;/span&gt;&lt;span&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;no_mangle&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-8&quot;&gt;pub&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-8&quot;&gt; extern&lt;/span&gt;&lt;span class=&quot;z-l-12 z-d-5&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-12 z-d-5&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;z-l-12 z-d-5&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-8&quot;&gt; fn&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-6&quot;&gt; add&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-3&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;z-d-8&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; i32&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-3&quot;&gt; b&lt;/span&gt;&lt;span class=&quot;z-d-8&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; i32&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-d-8&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; i32&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-3&quot;&gt;    a&lt;/span&gt;&lt;span class=&quot;z-d-8&quot;&gt; +&lt;/span&gt;&lt;span class=&quot;z-l-3&quot;&gt; b&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;宿主用 Windows 的 &lt;code&gt;LoadLibraryA&lt;/code&gt; / &lt;code&gt;GetProcAddress&lt;/code&gt; 加载库、查找函数。它自己也定义了一个 &lt;code&gt;Point&lt;/code&gt;，却把字段顺序写反了。下面节选类型声明和调用，&lt;code&gt;symbol_address&lt;/code&gt; 是已查到的函数地址；完整宿主源码见后文下载链接：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;repr&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;C&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-8&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; Point&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-3&quot;&gt;    y&lt;/span&gt;&lt;span class=&quot;z-d-8&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; i32&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-3&quot;&gt;    x&lt;/span&gt;&lt;span class=&quot;z-d-8&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; i32&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-4&quot;&gt;//&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-4&quot;&gt; 从查到的地址构造函数指针；声明由宿主自己保证正确。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-8&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;z-l-3&quot;&gt; new_fn&lt;/span&gt;&lt;span class=&quot;z-d-8&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-8&quot;&gt; extern&lt;/span&gt;&lt;span class=&quot;z-l-12 z-d-5&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-12 z-d-5&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;z-l-12 z-d-5&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-6&quot;&gt; fn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;i32&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; i32&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-d-8&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt; Point&lt;/span&gt;&lt;span class=&quot;z-d-8&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-8&quot;&gt; unsafe&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;    std&lt;/span&gt;&lt;span class=&quot;z-d-8&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-10&quot;&gt;mem&lt;/span&gt;&lt;span class=&quot;z-d-8&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-6&quot;&gt;transmute&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-3&quot;&gt;symbol_address&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-8&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;z-l-3&quot;&gt; p&lt;/span&gt;&lt;span class=&quot;z-d-8&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-6&quot;&gt; new_fn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-7 z-d-2&quot;&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-7 z-d-2&quot;&gt; 2&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-9 z-d-6&quot;&gt;println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-12 z-d-5&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-12 z-d-5&quot;&gt;point_new(1,2) -&amp;gt; x=&lt;/span&gt;&lt;span class=&quot;z-l-12 z-d-5&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;z-l-12 z-d-5&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;z-l-12 z-d-5&quot;&gt; y=&lt;/span&gt;&lt;span class=&quot;z-l-12 z-d-5&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;z-l-12 z-d-5&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;z-l-12 z-d-5&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-3&quot;&gt; p&lt;/span&gt;&lt;span class=&quot;z-d-8&quot;&gt;.&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-3&quot;&gt; p&lt;/span&gt;&lt;span class=&quot;z-d-8&quot;&gt;.&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在 rustc 1.94.0、&lt;code&gt;x86_64-pc-windows-msvc&lt;/code&gt; 环境下，这个实验打印：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;add(2,3) = 5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;point_new(1,2) -&amp;gt; x=2 y=1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;没有编译错误、链接错误，也没有崩溃。插件返回的第一个整数是 &lt;code&gt;1&lt;/code&gt;，宿主却把它当作 &lt;code&gt;y&lt;/code&gt;；第二个整数是 &lt;code&gt;2&lt;/code&gt;，宿主把它当作 &lt;code&gt;x&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;这个例子里，两个结构体的字段类型、大小和对齐恰好相同，交换字段名没有改变底层传递形状。错的是双方对这些字节的解释。它提醒我们：&lt;strong&gt;调用能完成，不等于接口约定一致。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;本文先解释这个 &lt;code&gt;Point&lt;/code&gt;，再看调用约定、符号、内存和失败处理。最后把它们对回上一篇《&lt;a href=&quot;https://blog.bigfisharc.cn/blog/20261015-0900-rpicha-jian-abijia-zai-ji-zhi/&quot;&gt;从一个 helloworld 动态库到 rpi package：ABI 插件是怎样被加载的&lt;/a&gt;》中的插件接口。不需要先读上一篇。&lt;/p&gt;</summary>
        
    </entry>
</feed>
