那曲檬骨新材料有限公司

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Rust重寫基礎軟件的實踐代碼

jf_wN0SrCdH ? 來源:Rust語言中文社區 ? 2024-01-19 10:05 ? 次閱讀

前言

受到2022年“谷歌使用Rust重寫Android系統且所有Rust代碼的內存安全漏洞為零” [1] 的啟發,最近筆者懷著濃厚的興趣也順應Rust 的潮流,嘗試著將一款C語言開發的基礎軟件轉化為 Rust 語言。本文的主要目的是通過記錄此次轉化過程中遇到的比較常見且有意思的問題以及解決此問題的方法與大家一起做相關的技術交流和討論。

問題描述

在項目轉化過程中我遇到了一個與 CAS (Compare and Swap) [2] 操作實現相關的問題,在計算機科學中CAS 是多線程/協程中用于實現同步的原子指令。該軟件針對不同的芯片平臺,通過在C語言中根據芯片平臺的類別進行宏定義并嵌入相應的匯編代碼來實現CAS操作。我知道不同芯片平臺對應的 CAS 操作的匯編代碼是不一樣的 [3],例如:

x86-64 (Intel/AMD) 需要類似如下匯編代碼塊:

lockcmpxchgq[destination],rdx

ARM 需要類似如下匯編代碼塊:

ldrexr1,[destination]
cmpr1,r2
strexeqr1,r2,[destination]

PowerPC 需要類似如下匯編代碼塊:

lwarxr0,0,destination
cmpwr0,r1
bneretry;branchifnotequal
stwcx.r2,0,destination
bneretry;branchifstorefailed

然而如下面的代碼片段所示,即使該軟件使用相同的Intel x86芯片平臺,但是在不同的操作系統平臺上其實現的匯編指令也有可能是不一樣的。

C頭文件中 cas_operation.h 的部分代碼如下:

#ifdefined(__i386)||defined(__x86_64__)||defined(__sparcv9)||defined(__sparcv8plus)
typedefunsignedintslock_t;
#else
typedefunsignedcharslock_t;
#endif
externslock_tmy_atomic_cas(volatileslock_t*lock,slock_twith,slock_tcmp);
#defineTAS(a)(my_atomic_cas((a),1,0)!=0)
#endif

對應實現的x86匯編文件 cas_operation.s 的部分代碼如下:

my_atomic_cas:
#ifdefined(__amd64)
movl%edx,%eax
lock
cmpxchgl%esi,(%rdi)
#else
movl4(%esp),%edx
movl8(%esp),%ecx
movl12(%esp),%eax
lock
cmpxchgl%ecx,(%edx)
#endif
Ret

眾所周知雖然Rust也有宏定義的包 Macros,但是目前也與C語言的有不小的差別。因此,在做轉化的過程中如何做到芯片平臺和操作系統級別的代碼兼容則是我遇到的最大挑戰。

解決方案

想到兩個解決方案:

使用asm! 宏去處理不同芯片平臺的匯編代碼

使用 Rust代碼對特定的操作進行針對性的實現

第一種方案比較簡單,只需要在代碼中使用std::asm 包,然后使用 asm! 宏(類似 println! 宏)去包裹不同平臺的匯編代碼即可,這也是最直接最容易想到的解決方案,而且無需考慮具體的匯編操作實現的指令和代碼。但是這方法雜糅了很多的不同平臺的匯編代碼,同時需要Rust做很多額外的平臺相關的邏輯控制,對這些控制邏輯部分代碼的維護也是一個持久且復雜的工作。比如對新的平臺指令 RSIC-V 的支持也要納入其中。

第二種方案則需要考慮具體的操作邏輯,然后通過Rust代碼去實現與匯編指令相同的邏輯,雖然有較大的工作量,但是這種方案可以消除由于芯片和系統平臺不同帶來的各種匯編代碼實現的差異。關于第一種方案的實現讀者可以參照文檔 Inline assembly [4] 中去做。針對 CAS 操作的第二種方案的實現則是本文主要提出的一種解決方案,而本文以類似Rust u32類型的 CAS 操作為例子實現其代碼,在 my_compare_and_swap.rs 中會有如下代碼段實現:

usestd::{AtomicU32,Ordering};

pubtypeuint32=libc::c_uint;
pubstructmy_atomic_uint32{
pubvalue:uint32,
}

implmy_atomic_uint32{
#[inline]
pubfncompare_and_swap(&self,expected:uint32,newval:uint32)->bool{
letatomic_ptr=selfas*constmy_atomic_uint32as*constAtomicU32;
letatomic=unsafe{&*(atomic_ptr)};
atomic.compare_and_swap(expected,newval,Ordering::SeqCst)==expected
}
}

pubfnmy_compare_and_swap_u32_impl(
mutptr:*mutpg_atomic_uint32,
mutexpected:*mutuint32,
mutnewval:uint32,
)->bool{
letatomic=&*ptr;
atomic.compare_and_swap(*expected,newval)
}

下面我來解釋一下上面的代碼。由于是從 C 轉到 Rust,因此我使用了 Rust 的 libc 包來自定義 uint32類型。然后通過自定義struct my_atomic_uint32 來對uint32進行CAS原子操作的包裹,同時對于此 struct實現其 inline 的compare_and_swap 操作函數。在該函數的實現中最關鍵的是將my_atomic_uint32的實體轉化為一個AtomicU32的常量(注意需要在 Rust 代碼文件開頭使用 std::{AtomicU32, Ordering} [5]),然后通過調用 AtomicU32 的compare_and_swap 來最終實現 uint32 的 CAS 操作。另外對于Ordering::SeqCst內存順序 [6] 的選擇也是比較考究的一個話題,這里我使用 SeqCst實際上是一個在保證正確的情況下不太考慮效率優化問題的選項。代碼的最后my_compare_and_swap_u32_impl 則是對外使用的 u32 的 CAS 操作(事實上該軟件主要也是需要實現 uint32 的 CAS 操作)。

結論

在本例中由于剛好有對應AtomicU32的CAS 實現,而且軟件中整個原子同步的代碼部分都是使用uint32進行的比較交換操作,因此我選擇第二種方案則是最佳選擇。由此可知上述的兩種解決方案其實是各有利弊的,我必須結合實際的應用場景才能去做決定。那么這里有一個問題,如果需要對許多數據類型(比如uint32, int32, uint64, int64, float, float32, float64……)進行比較交換操作,又該做何種選擇呢?這也許是仁者見仁智者見智的。

關于作者

張懷龍曾就職于阿爾卡特朗訊,百度,IBM等企業從事云計算研發相關的工作。目前就職于 Intel 中國,擔任云原生開發工程師并致力于云原生、服務網格等技術領域研究實踐,也是Istio 的maintainer的開發者。曾多次在 KubeCon、ServiceMeshCon、IstioCon、GOTC 和 InfoQ/QCon 等大會上發表演講。

審核編輯:黃飛

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • ARM
    ARM
    +關注

    關注

    134

    文章

    9168

    瀏覽量

    369217
  • Android
    +關注

    關注

    12

    文章

    3945

    瀏覽量

    127939
  • C語言
    +關注

    關注

    180

    文章

    7614

    瀏覽量

    137720
  • 匯編代碼
    +關注

    關注

    0

    文章

    24

    瀏覽量

    7567
  • Rust
    +關注

    關注

    1

    文章

    230

    瀏覽量

    6665

原文標題:一次Rust重寫基礎軟件的實踐(一)

文章出處:【微信號:Rust語言中文社區,微信公眾號:Rust語言中文社區】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    Rust GUI實踐Rust-Qt模塊

    Rust-Qt 是 Rust 語言的一個 Qt 綁定庫,它允許 Rust 開發者使用 Qt 框架來創建跨平臺的圖形界面應用程序。Qt 是一個跨平臺的應用程序框架,它提供了一系列的工具和庫,可以幫助
    的頭像 發表于 09-30 16:43 ?1667次閱讀

    Rust的 match 語句用法

    執行不同的代碼,這在處理復雜的邏輯時非常有用。在本教程中,我們將深入了解 Rust 的 match 語句,包括基礎用法、進階用法和實踐經驗等方面。 基礎用法 match 語句是 Rust
    的頭像 發表于 09-19 17:08 ?968次閱讀

    Rust的多線程編程概念和使用方法

    和字段、常見用法以及多線程的一些實踐經驗。由淺入深帶你零基礎玩轉Rust的多線程編程。 線程的基本概念和使用方法 Thread是Rust中并發編程的一種基本方式。Rust中的Threa
    的頭像 發表于 09-20 11:15 ?1026次閱讀

    如何編寫高性能的Rust代碼

    為了最大限度地提高Rust應用程序的性能,你需要了解支持代碼的底層硬件架構,如何優化算法和數據結構,以及如何對代碼進行配置和基準測試。在本文中,我們將簡要介紹這些主題,希望能更好地理解如何編寫高性能的
    的頭像 發表于 11-03 14:28 ?896次閱讀
    如何編寫高性能的<b class='flag-5'>Rust</b><b class='flag-5'>代碼</b>

    Rust代碼中加載靜態庫時,出現錯誤 ` rust-lld: error: undefined symbol: malloc `怎么解決?

    “ [i]malloc ”、“ [i]exit ”。我驗證了使用 ` [i]nm ` 命令。 問題是我打算使用 ffi 在 rust 中使用這個靜態庫。當我嘗試在我的 Rust 代碼中加載靜態庫
    發表于 06-09 08:44

    微軟開發基于Rust的新編程語言,將很快開源

    此前,微軟表示正探索將Rust作為C和C++的安全替代方案,并且也對外展示了使用Rust重寫Windows組件的體驗,根據微軟的說法,Rust是一種從根本上考慮安全性的編程語言,他們將
    的頭像 發表于 12-03 10:36 ?3960次閱讀

    Chromium正式開始支持Rust

    ? Chromium 正式開始支持 Rust 目前的支持只是第一階段,在C++代碼中使用Rust寫的第三方庫(編譯成.so)。估計明年Chromium的二進制發行文件中會包含rust
    的頭像 發表于 01-14 10:04 ?1026次閱讀

    Cloudflare用Rust重寫Nginx C模塊,構建沒有Nginx的未來

    近日,Cloudflare 工程師介紹了如何使用 Rust 重寫基于 C 語言的 Nginx 模塊。Cloudflare 工程師在博客寫道,他們用 Rust 為 Cloudflare 基礎設施中最
    的頭像 發表于 03-08 09:36 ?800次閱讀

    如何在同步的Rust方法中調用異步代碼呢?

    在同步的 Rust 方法中調用異步代碼經常會導致一些問題,特別是對于不熟悉異步 Rust runtime 底層原理的初學者。
    的頭像 發表于 03-17 09:18 ?2198次閱讀

    Rust重寫的LSP:KCL IDE 插件的功能介紹與設計解析

    在這次更新中,我們發布了全新的 KCL VS Code 插件,并且用 Rust 重寫了 LSP 的 Server 端。我們提供了 IDE 中常用的代碼輔助功能,如高亮、跳轉、補全、Outline、懸停、錯誤提示等。
    的頭像 發表于 05-11 09:39 ?1018次閱讀
    <b class='flag-5'>Rust</b><b class='flag-5'>重寫</b>的LSP:KCL IDE 插件的功能介紹與設計解析

    Windows 11初嘗Rust,36000行內核代碼重寫

    更早些時候,微軟用 Rust 重寫了 DirectWrite Core 庫的概念驗證,它是 Windows 的 DWrite 引擎的 Windows App SDK 實現,用于文本分析、布局和渲染
    的頭像 發表于 05-19 16:39 ?1053次閱讀
    Windows 11初嘗<b class='flag-5'>Rust</b>,36000行內核<b class='flag-5'>代碼</b>已<b class='flag-5'>重寫</b>!

    rust語言基礎學習: rust中的錯誤處理

    錯誤是軟件中不可避免的,所以 Rust 有一些處理出錯情況的特性。在許多情況下,Rust 要求你承認錯誤的可能性,并在你的代碼編譯前采取一些行動。
    的頭像 發表于 05-22 16:28 ?2188次閱讀

    Rust的內部工作原理

    Rust到匯編:了解 Rust 的內部工作原理 非常好的Rust系列文章,通過生成的匯編代碼,讓你了解很多Rust內部的工作機制。例如文章有
    的頭像 發表于 06-14 10:34 ?841次閱讀
    <b class='flag-5'>Rust</b>的內部工作原理

    一次Rust重寫基礎軟件實踐

    受到2022年“谷歌使用Rust重寫Android系統且所有Rust代碼的內存安全漏洞為零” [1] 的啟發,最近筆者懷著濃厚的興趣也順應Rust
    的頭像 發表于 01-25 11:21 ?698次閱讀

    [鴻蒙]OpenHarmony4.0的Rust開發

    背景 Rust 是一門靜態強類型語言,具有更安全的內存管理、更好的運行性能、原生支持多線程開發等優勢。Rust 官方也使用 Cargo 工具來專門為 Rust 代碼創建工程和構建編譯
    的頭像 發表于 02-26 17:28 ?958次閱讀
    [鴻蒙]OpenHarmony4.0的<b class='flag-5'>Rust</b>開發
    澳门百家乐必胜看| 全讯网百家乐的玩法技巧和规则| 百家乐游戏机压法| 中国百家乐官网软件| 百家乐官网大小牌路的含义| 老人头百家乐的玩法技巧和规则| 皇冠百家乐皇冠网| 百家乐api| 大发888电话多少| 新皇冠现金网| 百家乐官网如何投注法| 百家乐官网在线娱乐网| 百家乐官网赌博工具| 属猪的做生意门朝向| 聚龍社百家乐的玩法技巧和规则| 百家乐游戏试| 多台百家乐的玩法技巧和规则| 大发888娱乐城 真钱下载| 百家乐官方网站| 金盾百家乐官网网址| 百家乐送彩金平台| 百家乐可以破解吗| 波胆| 大发888官方下载168| 顶尖百家乐官网学习| 中国百家乐官网的玩法技巧和规则| 百家乐官网专用| 励骏会百家乐的玩法技巧和规则| 联众博彩| 百家乐官网赌博信息| 百家乐投注技巧公式| bet365备用网| 百家乐官网好赌吗| 百家乐赌场详解| 大化| 百家乐官网技巧公司| 百家乐三遍| 大发888亚洲游戏下载| 宝清县| 百家乐官网真人游戏攻略| 百家乐玩揽法大全|