پرش به محتوای اصلی
پرش به محتوای مقاله

Rust در برابر C++؛ بازنویسی mold برای حذف آسیب‌پذیری‌های حافظه

·۱۳ مهر ۱۴۰۵۶ دقیقه مطالعه۱ بازدید
نسخه ۳.۰.۰ پیوندگر mold منتشر شد: بهبود سرعت، پشتیبانی از معماری‌های جدید و رفع اشکالات.
نسخه ۳.۰.۰ پیوندگر mold منتشر شد: بهبود سرعت، پشتیبانی از معماری‌های جدید و رفع اشکالات.
اشتراک‌گذاری
واقعاً چه چیز جدید است؟

بازنویسی کامل هسته ابزار از C++ به Rust بدون افت سرعت؛ تبدیل یک ابزار سریع اما مستعد کرش به یک ابزار سریع و ایمن از نظر حافظه.

اگر زمان طولانی کامپایل پروژه‌های بزرگ C++ یا Rust شما را کلافه کرده است، ابزاری که قرار است این گلوگاه را از بین ببرد، حالا امن‌تر و پایدارتر شده است. mold در نسخه ۳.۰.۰ با یک چرخش بنیادین، تمام کدهای خود را از C++ به Rust منتقل کرد تا سرعت خیره‌کننده خود را با ایمنی حافظه ترکیب کند. این تغییر استراتژیک با هدف حذف آسیب‌پذیری‌های مربوط به ایمنی حافظه صورت گرفته است، در حالی که سرعت فوق‌العاده‌ای که ویژگی اصلی این ابزار است، کاملاً حفظ شده است. همان‌طور که در یادداشت‌های انتشار نسخه ۲.۴۲.۱ ذکر شده، آن نسخه آخرین انتشار مبتنی بر C++ بود و نسخه ۳.۰.۰ نخستین نسخه بازنویسی‌شده با Rust است.

برای درک اهمیت این خبر، ابتدا باید بدانیم لینکر (Linker) — شبیه به یک تکه‌دوز حرفه‌ای که قطعات مختلف پارچه را به هم می‌دوزد تا یک لباس کامل شود — آخرین مرحله از فرآیند ساخت نرم‌افزار است که فایل‌های شیء (Object Files) را به یک فایل اجرایی واحد تبدیل می‌کند. در حالی که GNU ld استاندارد صنعت است، اما در پروژه‌های مقیاس‌بزرگ C++ یا Rust به‌شدت کند عمل می‌کند و اغلب به یک گلوگاه تبدیل می‌شود. mold برای حل این مشکل طراحی شد و اکنون انتقال به Rust یک حرکت استراتژیک است تا این ابزار به اندازه کافی پایدار شود که به عنوان پیش‌فرض سیستم در توزیع‌های لینوکس قرار گیرد. هدف سری ۳.x این است که شکاف‌های سازگاری باقی‌مانده با GNU ld، به‌ویژه در پشتیبانی از اسکریپت‌های لینکر، کاملاً پر شود.

به نقل از مستندات رسمی در گیت‌هاب، نسخه C++ ابزار mold در مواجهه با فایل‌های ورودی خراب، به دلیل خواندن حافظه خارج از محدوده (out-of-bounds memory reads)، دچار خطاهای Segmentation Fault می‌شد. در mold 3.0، تمام این عملیات‌ها اکنون دارای بررسی محدوده (bounds-checked) هستند. به‌جای یک کرش ناگهانی و خاموش یا ایجاد یک آسیب‌پذیری امنیتی، لینکر اکنون در نقطه دسترسی اشتباه، یک «Panic» کنترل‌شده را فعال می‌کند.

تیم توسعه برای اطمینان از اینکه عملکرد ابزار با نسخه ۲.۴۲.۱ برابری می‌کند، تمام بسته‌های Gentoo را با نسخه جدید ساختند و مجموعه‌ای جامع از تست‌ها را روی تمامی معماری‌های مورد پشتیبانی اجرا کردند تا مطمئن شوند هیچ پس‌رفت (Regression) در بازنویسی رخ نداده است. آن‌ها خروجی لینکر را در طیف گسترده‌ای از حجم‌های کاری واقعی و ترکیبات مختلف گزینه‌ها مقایسه کردند تا تأیید کنند mold 3.0 یک جایگزین مستقیم (Drop-in replacement) برای نسخه ۲.۴۲.۱ است؛ به این معنا که همان گزینه‌های خط فرمان را می‌پذیرد و از همان معماری‌های هدف پشتیبانی می‌کند.

ساختار سیستم ساخت (Build System) نیز به‌طور کامل تغییر کرده است. این پروژه CMake را کنار گذاشته و اکنون از Cargo — مدیر بسته‌های زبان Rust — استفاده می‌کند. متغیر CMake با نام MOLD_TARGETS اکنون با ویژگی‌های (Features) Cargo جایگزین شده است و مجموعه تست‌ها به‌جای ctest با دستور cargo test اجرا می‌شوند.

جزئیات فنی تغییرات زیرساختی عبارتند از:

  • نیازمندی‌ها: کاربران اکنون به Rust 1.95 یا نسخه‌های جدیدتر و یک کامپایلر استاندارد C نیاز دارند. اسکریپت install-build-deps.sh با install-test-deps.sh جایگزین شده که فقط برای اجرای تست‌ها مورد نیاز است.
  • فرآیند ساخت: ابزار با دستور cargo build --release ساخته شده و از طریق اسکریپت install-mold.sh نصب می‌شود. این اسکریپت نصب، متغیرهای PREFIX و DESTDIR را می‌پذیرد.
  • وابستگی‌ها: mold دیگر به oneTBB وابسته نیست. این ابزار همچنان mimalloc 3.5.3 را به‌صورت استاتیک لینک می‌کند، هرچند کاربران می‌توانند با پرچم --features system-allocator از تخصیص‌کننده سیستم استفاده کنند. همچنین در صورت موجود بودن، zlib سیستم را لینک می‌کند و شامل zstd و BLAKE3 است؛ کاربران می‌توانند برای لینک کردن zstd سیستم، مقدار ZSTD_SYS_USE_PKG_CONFIG=1 را تنظیم کنند.
  • مدیریت کتابخانه‌ها: اگر کتابخانه‌ها خارج از پیش‌فرض (مثلاً در /usr/lib64) نصب شده باشند، کاربران باید متغیر محیطی MOLD_LIBDIR را تنظیم کنند تا mold -run بتواند Wrapper را پیدا کند.

طبق گزارش گیت‌هاب، یکی از اولویت‌های سری ۳.x، پر کردن شکاف‌های سازگاری با GNU ld است. در این نسخه، چندین باگ بحرانی رفع شده است:

  • پایداری: رفع کرش‌ها هنگام ساخت فایل‌های اجرایی با لینک استاتیک که از اسکریپت‌های نسخه یا --default-symver استفاده می‌کردند. همچنین کرش‌ها یا خروجی‌های خراب در حالتی که فایل خروجی همزمان فایل ورودی بود (مانند mold -r -o foo.o foo.o bar.o) برطرف شد.
  • مدیریت نمادها: نمادهای رایج با نام یکسان اما اندازه‌های متفاوت، اکنون بزرگترین اندازه و سخت‌گیرانه‌ترین تراز (Alignment) را می‌پذیرند که دقیقاً مشابه رفتار GNU ld و lld است. علاوه بر این، گزینه --gc-sections دیگر توابعی را که توسط --init و --fini ارائه شده‌اند، حذف نمی‌کند.
  • بهبودهای ICF: گزینه --icf=safe دیگر توابع صادر شده از کتابخانه‌های مشترک (Shared Libraries) را ادغام (Fold) نمی‌کند و --icf=all هنگام استفاده با --emit-relocs دیگر باعث کرش نمی‌شود.
  • خروجی‌های قطعی: تیم توسعه چندین مورد از خروجی‌های غیرقطعی (Non-deterministic) را که بر --dependency-file، --repro، جابه‌جایی‌های پویا (Dynamic Relocations) و دستور -r با گروه‌های COMDAT هم‌نام اثر می‌گذاشت، حل کرد.
  • تجزیه خط فرمان: گزینه‌هایی که با یک خط تیره شروع می‌شوند، اکنون دقیقاً مشابه GNU ld خوانده می‌شوند. برای مثال، -entry=main دیگر به‌اشتباه به صورت -e ntry=main تفسیر نمی‌شود.
  • گزارش خطا: خطاهای مربوط به جابه‌جایی‌های PC-relative که در خروجی‌های مستقل از موقعیت (Position-independent) قابل استفاده نیستند، اکنون علت و راه حل را توضیح می‌دهند. همچنین برای مواردی مانند --defsym که نمادی در کتابخانه مشترک را مستعار می‌کند یا مقداری بیش از ۶۴ بیت دارد، به‌جای تولید خروجی خراب، خطاهای جدیدی صادر می‌شود.

در بخش معماری‌های غیر x86 نیز پیشرفت‌های چشمگیری رخ داده است. برای AArch64، PPC32 و ARM32، آدرس‌های پرش در range extension thunks اصلاح شدند؛ مشکلی که پیش از این باعث شکست در کامپایل برنامه‌های عظیم مانند Chromium در حالت دیباگ ARM64 می‌شد.

جزئیات تکمیلی معماری‌ها:

  • AArch64: پشتیبانی از انواع جابه‌جایی‌های بیشتر، از جمله R_AARCH64_TSTBR14 و R_AARCH64_GOT_LD_PREL19 اضافه شد.
  • ARM32: پشتیبانی از R_ARM_ALU_PC_G0 و R_ARM_THM_PC12 اضافه شد و خروجی -r برای ARM با Endian بزرگ اصلاح گردید. همچنین در کنار i386، دستور -r دیگر دستورالعمل‌های مربوط به برخی جابه‌جایی‌های Branch و TLS را خراب نمی‌کند.
  • RISC-V و LoongArch: مشکلات ادغام توابع هنگام کوچک شدن آن‌ها توسط Relaxation رفع شد و جابه‌جایی‌های R_RISCV_64 و R_LARCH_64 در اشیاء ۳۲ بیتی اصلاح شدند. RISC-V همچنین اصلاحاتی برای TLSDESC با Clang 18 و پرچم EF_RISCV_TSO دریافت کرد.
  • LoongArch: پشتیبانی از TLSDESC در مدل کد extreme اضافه شد و جابه‌جایی‌های *64_PC_HI12 اصلاح شدند.
  • PPC32 و m68k: اگر GOT برای آفست‌های ۱۶ بیتی مورد استفاده در کدهای -fpic بیش از حد بزرگ باشد، اکنون به‌جای حذف خاموش، به‌صورت خطا گزارش می‌شود.
  • PPC64: فراخوانی‌های IFUNC در فایل‌های اجرایی با لینک استاتیک و ارجاعات @got در اسمبلی‌های دست‌نویس اصلاح شدند. mold اکنون خانواده توابع _savegpr0_* را برای PPC64V1 سنتز می‌کند.
  • SH4 و SPARC64: کرش‌های SH4 هنگام فراخوانی توابعی که ساختارها را از طریق PLT برمی‌گردانند، رفع شد. SPARC64 نیز اصلاحاتی برای R_SPARC_WDISP16 و R_SPARC_OLO10 در خروجی -r دریافت کرد.

در زمینه مدیریت منابع، در یک تغییر کلیدی، mold 3.0 دیگر در لحظه شروع، ۸ گیگابایت فضای آدرس مجازی رزرو نمی‌کند. این تغییر اجازه می‌دهد لینکر تحت محدودیت‌های سخت‌گیرانه ulimit -v به‌درستی کار کند و آن را برای محیط‌های CI/CD محدود، کاربردی‌تر می‌کند. علاوه بر این، MOLD_JOBS اکنون حتی اگر XDG_RUNTIME_DIR یک رشته خالی باشد، به‌درستی عمل می‌کند.

سایر پاک‌سازی‌ها شامل حذف نمادهای بی‌معنی مانند __start_EHDR، __stop_EHDR، __start_PHDR و __stop_PHDR است. همچنین فایل‌های ایجاد شده توسط --separate-debug-file دیگر شامل بخش .gnu_debuglink نمی‌شوند.

این بازنویسی، فرضیات قدیمی درباره ابزارهای سیستمی با کارایی بالا را به چالش می‌کشد. mold ثابت کرد که ایمنی حافظه لزوماً به قیمت کاهش سرعت اجرا تمام نمی‌شود. این پروژه همچنان توسط حامیان در GitHub Sponsors و OpenCollective و سازمان‌هایی مانند SAP، Mercedes-Benz Group و Cybozu, Inc. حمایت می‌شود.

گام بعدی شما

  • اگر از نسخه ۲.۴۲.۱ استفاده می‌کنید، همین امروز به نسخه ۳.۰.۰ به‌روزرسانی کنید تا از پایداری بیشتر و سازگاری بهبودیافته با GNU ld بهره‌مند شوید.
  • در محیط‌های CI/CD خود، محدودیت‌های حافظه مجازی را تست کنید تا اثر حذف رزرو ۸ گیگابایتی را مشاهده کنید.
  • برای پروژه‌های ARM64، سازگاری جدید در لینک کردن برنامه‌های حجیم را بررسی کنید.

منتظر تلاش‌های ادغام در آینده باشید، زیرا توزیع‌های بزرگ لینوکس شروع به تست mold به عنوان جایگزین پیش‌فرض برای لینکر قدیمی GNU کرده‌اند.

اما داستان سخت‌افزاری این تحول حتی شگفت‌انگیزتر است — به تحلیل ما درباره‌ی تراشه‌های Blackwell مراجعه کنید.

چرا این موضوع مهم است؟

این تغییر با تکیه بر اعتبار جامعه Rust، ریسک‌های امنیتی مربوط به مدیریت حافظه را در یکی از حساس‌ترین نقاط زنجیره ساخت نرم‌افزار حذف می‌کند. پذیرش mold به‌عنوان پیش‌فرض در توزیع‌های لینوکس، می‌تواند زمان کامپایل هزاران پروژه متن‌باز را به‌طور چشم‌گیر کاهش دهد.

تأثیر برای ایران

این ابزار به‌صورت متن‌باز است و توسعه‌دهندگان ایرانی می‌توانند برای کاهش زمان Build پروژه‌های سنگین C++/Rust از آن استفاده کنند. دسترسی به آن هیچ محدودیتی ندارد.

·نگاه ما
تحریریه دات‌هوش

انتقال یک ابزار زیرساختی مانند لینکر به Rust، نشان‌دهنده بلوغ این زبان در لایه‌های بسیار پایین سیستم‌عامل است. این حرکت فراتر از یک به‌روزرسانی فنی است؛ در واقع mold در حال تبدیل شدن از یک «ابزار جایگزین برای کاربران پیشرفته» به یک «استاندارد سیستمی» است که توزیع‌های لینوکس بتوانند با اطمینان از پایداری آن، آن را جایگزین GNU ld کنند.

منابع

این گزارش با خط‌لولهٔ خودکار دات‌هوش از منابع معتبر جهانی تدوین و زیر نظر تحریریه منتشر شده است. روش کار ما

گفتگو

پنج‌شنبه‌های هوش‌محور

بسته‌ی هفتگی دات‌هوش

۵ خبر، ۲ ابزار، ۱ پرامپت در هر شماره. به‌زودی راه‌اندازی می‌شود — هر پنج‌شنبه صبح.

خبر کلیدی
ابزار کاربردی
پرامپت حرفه‌ای
تحلیل پژوهش
به‌زودی
زاویه‌ی ایرانی
به‌زودی
تمرین این هفته
به‌زودی

راهنماهای دات‌هوش

راهنماهای کاربردیِ دات‌هوش برای کار با هوش مصنوعی — از همین‌جا شروع کنید:

دات‌هوش

راهنمای فارسی هوش مصنوعی — با نگاه به ایران

اخبار روزانه، معرفی ابزارها و مدل‌ها، و آموزشِ کار با هوش مصنوعی؛ همیشه با این پرسش که از ایران چه چیزی کار می‌کند و چه چیزی نه.