يستخدم هذا المشروع MSVC C ++ STL في برنامج تشغيل Windows kernel. في هذا الحل ، يتم تنفيذ jxystl.lib باعتباره كيرنيل مُثبّت ، ونوع علامة التجمع/العلامة ، ومكتبة القالب وتطبيق MSVC. التي ، تحت الغطاء ، يستخدم MSVC C ++ STL.
# include < wdm.h >
# include < jxy/string.hpp >
extern " C "
NTSTATUS DriverEntry (
PDRIVER_OBJECT DriverObject,
PUNICODE_STRING RegistryPath)
{
jxy::wstring<PagedPool, ' 0GAT ' > helloWorld;
try
{
helloWorld. assign ( L" Hello, World! " );
}
catch ( const std::bad_alloc&)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
return STATUS_SUCCESS;
} 1: kd> dv
DriverObject = 0xffffca83`5380d300 Driver "Driverstlkrn"
RegistryPath = 0xffffca83`5227f000 "REGISTRYMACHINESYSTEMControlSet001Servicesstlkrn"
helloWorld = "Hello, World!"
| معيار | مدعوم | ملحوظات |
|---|---|---|
| CPP11 | لا | لم يخبر ، أرادتك تختلف |
| CPP14 | نعم | |
| CPP17 | نعم | |
| CPP20 | نعم |
يضم برنامج تشغيل الاختبار في هذا الحل ، stdtest.sys ، اختبارات الوحدة للمشروع. يتم تشغيل اختبارات الوحدة في kernel مع محقة السائق. إطار اختبار الوحدة هو عظام عارية ولكنه يكفي لممارسة jxystl.lib .
سائق آخر تم تنفيذه في هذا الحل ، stdkrn.sys ، يضع jxystl.lib لاستخدامه في سيناريو عملي. يستخدم العديد من مرافق مساحة الاسم std والحاويات (ملفوفة تحت مساحة اسم jxy ). يسجل برنامج التشغيل هذا الإخطارات العملية والخيط والتصوير ؛ ثم يستخدم C ++ الحديث لتتبع سياقات العملية وسياقات مؤشر الترابط وسياقات الوحدة النمطية.
vcrtlتتيح معالجة الاستثناءات كائنات C ++ للاسترخاء عند إلقاء استثناء. هذه ميزة أساسية لـ C ++ والتي تحظى باهتمام كبير لسائقي kernel. لا تدعم Microsoft استثناءات C ++ أصلاً لسائقي kernel.
أصبح معالجة استثناء C ++ ممكنة بواسطة Avakar's VCRTL Libraray. كان هذا المشروع أكثر من ذلك بكثير من العمل دون مساهمة Avakar الرائعة. للحصول على معلومات حول معالجة استثناء في Windows ، توجه برامج التشغيل إلى VCRTL Github من Avakar. أيضًا ، تقدم هذه الصفحة تفاصيل ممتازة حول معالجة الاستثناء على AMD64.
jxystlترتبط تخصيصات النوافذ النوافذ بتجمع الذاكرة. علاوة على ذلك ، تم تصميم علامة تجمع في نوافذ النوافذ. تجمع العلامات تسهل تتبع المخصصات التي يقوم بها السائقون. تتيح منشأة وضع العلامات هذا تصحيح الأخطاء ومراقبة المخصصات.
تمكّن مساحة اسم jxy ، في هذا الحل ، تطوير برامج تشغيل Windows باستخدام كائنات مساحة الاسم std مع كتابة التجمع والعلامات.
تختار المكتبة عدم تنفيذ مشغلي "عالمي" new / delete . إنه ينفذ فقط المشغلات new / delete مع إمكانية كتابة تجمع وإمكانية وضع العلامات. هذا يتطلب تحديد أنواع البلياردو والعلامات. إذا تم استخدام بعض الوظائف التي تتطلب "مخصصًا عالميًا" ، فلن تربطها. هذا قرار تصميم مقصود بحيث لا يتم استخدام أي مخصصات عالمية ، يجب على جميع المخصصات تحديد نوع التجمع وعلامة.
تقوم مساحة اسم jxy بتنفيذ مخصصات وحذف يتوافق مع المعيار للاستخدام في حاويات القالب. هؤلاء المخصصون والحذف هم نوع التجمع/العلامة على دراية. أنها تتطلب تحديد نوع التجمع ووضع العلامة ومنع التحويلات/إعادة التشويش عبر أنواع الأدوات والعلامات - يجب استخدامها بدلاً من مخصصات STL.
jxy::allocator<T, PagedPool, ' 0GAT ' >;
jxy::default_delete<T, PagedPool, ' 0GAT ' >; jxystl.lib ينفذ وظيفة "ملء" ضرورية لاستخدام حاويات MSVC STL. التطبيقات (في msvcfill.cpp ) هي مراعاة في kernel. تتيح هذه الوظيفة حاويات MSVC STL من الارتباط بوظائف kernel المناسبة. هذا يعني أيضًا أنه إذا تم استخدام بعض وظائف حاوية std التي لا تحتوي على وظيفة "ملء" وراءها - فسوف يفشل الرابط. هذا قرار تصميم مقصود بحيث يتم التفكير في أي تطبيقات من خلال الاستخدام في النواة.
تهيئة CRT ووظيفة atexit غير مدعومة عمدا. ترتيب تهيئة CRT غير واضح وغير واضحة. عندما يقوم برنامج تشغيل kernel بتحميل البيانات العالمية ، يجب أن يتم إعدادها وهرعها أثناء تحميل برنامج التشغيل وتفريغها. تهيئة CRT العالمية "تخفي" هذا التهيئة بطريقة غير واضحة. علاوة على ذلك ، لا يتم دعم وظيفة CRT atexit. لا يتم انبعاث التزامن اللازم الذي يتيح التهيئة الثابتة المحلية لكائنات C ++ بواسطة المترجم. ويقدم التزامن غير الودي في النواة. عدم تهيئة CRT ودعم ATEXIT هو قرار التصميم المتعمد. أوصي بشدة بتجنب ذلك عند تطوير برامج تشغيل kernel.
على سبيل المثال ، فإن مساحة اسم jxy "لفات" std::vector وقوات استخدام أنواع البلياردو والعلامات:
namespace jxy
{
template < typename T,
POOL_TYPE t_PoolType,
ULONG t_PoolTag,
typename TAllocator = jxy::allocator<T, t_PoolType, t_PoolTag>>
using vector = std::vector<T, TAllocator>;
}
jxy::vector< int , PagedPool, ' 0GAT ' > integers; stlkrn!DriverEntry+0xea:
0: kd> dx integers
integers : { size=10 } [Type: std::vector<int,jxy::details::allocator<int,1,809976148> >]
[<Raw View>] [Type: std::vector<int,jxy::details::allocator<int,1,809976148> >]
[capacity] : 10
[allocator] : {...} [Type: std::_Compressed_pair<jxy::details::allocator<int,1,809976148>,std::_Vector_val<std::_Simple_types<int> >,1>]
[0] : 1 [Type: int]
[1] : 2 [Type: int]
[2] : 3 [Type: int]
[3] : 4 [Type: int]
[4] : 5 [Type: int]
[5] : 6 [Type: int]
[6] : 7 [Type: int]
[7] : 8 [Type: int]
[8] : 9 [Type: int]
[9] : 10 [Type: int]
فيما يلي جدول الوظائف تحت مساحة اسم jxy :
| jxy | مكافئ STL | يشمل | ملحوظات |
|---|---|---|---|
jxy::allocator | std::allocator | <jxy/memory.hpp> | |
jxy::default_delete | std::default_delete | <jxy/memory.hpp> | |
jxy::unique_ptr | std::unique_ptr | <jxy/memory.hpp> | |
jxy::shared_ptr | std::shared_ptr | <jxy/memory.hpp> | |
jxy::basic_string | std::basic_string | <jxy/string.hpp> | |
jxy::string | std::string | <jxy/string.hpp> | |
jxy::wstring | std::wstring | <jxy/string.hpp> | |
jxy::vector | std::vector | <jxy/vector.hpp> | |
jxy::map | std::map | <jxy/map.hpp> | |
jxy::multimap | std::miltimap | <jxy/map.hpp> | |
jxy::mutex | std::mutex | <jxy/locks.hpp> | يستخدم KGUARDED_MUTEX |
jxy::shared_mutex | std::shared_mutex | <jxy/locks.hpp> | يستخدم EX_PUSH_LOCK |
jxy::unique_lock | std::unique_lock | <jxy/locks.hpp> | |
jxy::shared_lock | std::shared_lock | <jxy/locks.hpp> | |
jxy::scope_resource | لا أحد | <jxy/scope.hpp> | على غرار std::experimental::unique_resource |
jxy::scope_exit | لا أحد | <jxy/scope.hpp> | على غرار std::experimental::scope_exit |
jxy::thread | std::thread | <jxy/thread.hpp> | |
jxy::deque | std::deque | <jxy/deque.hpp> | |
jxy::queue | std:queue | <jxy/queue.hpp> | |
jxy::priority_queue | std::priority_queue | <jxy/queue.hpp> | |
jxy::set | std::set | <jxy/set.hpp> | |
jxy::multiset | std::multiset | <jxy/set.hpp> | |
jxy::stack | std::stack | <jxy/stack.hpp> |
stltest.sys يقوم مشروع stltest بتنفيذ برنامج تشغيل يقوم ببعض الاختبارات ضد JXYSTL ، واستخدام STL ، والاستثناءات في Kernel Windows.
stlkrn.sys مشروع stlkrn هو برنامج تشغيل Windows يستخدم jxystl.lib لتنفيذ العملية والمعلومات وتتبع الوحدة النمطية في Kernel Windows.
سجلات stlkrn.sys لعملية الإخطارات والخيط والمعلومات باستخدام الوظائف التي تم تصديرها بواسطة ntoskrnl . باستخدام هذه العوائد ، فإنه يتتبع العمليات ، وموضوعات الخيوط ، وتحميل الصور في كائنات مختلفة تستخدم jxy::map ، jxy::shared_mutex ، jxy::wstring ، والمزيد.
السائق لديه اثنين من singletons. jxy::ProcessMap و jxy::ThreadMap ، يتم إنشاء هذه عندما يتم تحميل برنامج التشغيل ( DriverEntry ) وهدم عند تفريغ برنامج التشغيل ( DriverUnload ). تجدر الإشارة هنا إلى تتبع كل عملية تتبع في jxy::ProcessMap (التي تم تنفيذها كـ jxy::ProcessContext ) تدير أيضًا jxy::ThreadMap . كل "سياق" ( jxy::ProcessContext و jxy::ThreadContext و jxy::ModuleContext ) هو كائن مشترك (مشار إليه) ( jxy::shared_ptr ). لذلك ، فإن سياق الخيط الموجود في خريطة الخيط المفردة هو نفس السياق المرتبط بسياق العملية.
المكونات الرئيسية لـ stlkrn.sys :
| هدف | غاية | مصدر | ملحوظات |
|---|---|---|---|
jxy::ProcessContext | معلومات لعملية تعمل على النظام. | process_context.hpp/cpp | يستخدم jxy::wstring . لديه موضوع ( jxy::ThreadMap ) والوحدة ( jxy::ModuleMap ) خريطة أعضاء. |
jxy::ThreadContext | معلومات لخيط يعمل على النظام. | thread_context.hpp/cpp | يستخدم std::atomic . |
jxy::ModuleContext | معلومات عن صورة تم تحميلها في عملية معينة. | module_context.hpp/cpp | يستخدم jxy::wstring و jxy::shared_mutex . |
jxy::ProcessMap | Singleton ، Maps Carch jxy::ProcessContext كائنات إلى PID. | process_map.hpp/cpp | يتم الوصول إلى Singleton عبر jxy::GetProcessMap . يستخدم jxy::shared_mutex و jxy::map . |
jxy::ThreadMap | الخرائط المشتركة jxy::ThreadContext كائنات إلى tid. | thread_map.hpp/cpp | يتم الوصول إلى جدول الخيوط العالمية (Singleton) عبر jxy::GetThreadMap . يحتوي كل jxy::ProcessContext أيضًا على خريطة مؤشر ترابط يتم الوصول إليها من خلال jxy::ProcessContext::GetThreads . يستخدم jxy::shared_mutex و jxy::map . |
jxy::GetModuleMap | الخرائط المشتركة jxy::ModuleContext إلى نطاقات صورة محملة (العنوان الأساسي والعنوان). | module_map.hpp/cpp | كل سياق العملية لديه عضو في خريطة الوحدة. يتم تتبع الصور المحملة لعملية معينة باستخدام هذا الكائن. يستخدم jxy::shared_mutex و jxy::map |
std::unordered_map كان خيارًا أفضل على الشجرة المطلوبة ( std::map ) لخرائط الكائن. هناك سبب لم يتم استخدامه (انظر قسم TODO ).
stlkrn!jxy::nt::CreateProcessNotifyRoutine+0xa6:
3: kd> dx proc
proc : {...} [Type: std::shared_ptr<jxy::ProcessContext>]
[<Raw View>] [Type: std::shared_ptr<jxy::ProcessContext>]
[ptr] : 0xffffaa020d73cf70 [Type: jxy::ProcessContext *]
[control block] : custom deleter, custom allocator [Type: std::_Ref_count_resource_alloc<jxy::ProcessContext *,jxy::details::default_delete<jxy::ProcessContext,1,1668307018>,jxy::details::allocator<jxy::ProcessContext,1,1668307018> > (derived from std::_Ref_count_base)]
[+0x000] m_ProcessId : 0x2760 [Type: unsigned int]
[+0x004] m_SessionId : 0x2 [Type: unsigned int]
[+0x008] m_ParentProcessId : 0xcc4 [Type: unsigned int]
[+0x010] m_FileName : "DeviceHarddiskVolume4WindowsSystem32cmd.exe" [Type: std::basic_string<unsigned short,std::char_traits<unsigned short>,jxy::details::allocator<unsigned short,1,1852856394> >]
[+0x030] m_FilePart : "cmd.exe" [Type: std::basic_string<unsigned short,std::char_traits<unsigned short>,jxy::details::allocator<unsigned short,1,1886410826> >]
[+0x050] m_CreatorProcessId : 0x1b08 [Type: unsigned int]
[+0x054] m_CreatorThreadId : 0x26a0 [Type: unsigned int]
[+0x058] m_Threads [Type: jxy::ThreadMap]
[+0x070] m_Modules [Type: jxy::ModuleMap]
كنت أرغب في تضمين std::unordered_map في البداية ، ومع ذلك يستخدم ceilf . يأتي الحساب العائم في نوافذ النوافذ مع بعض التحديات. لذلك ، يتم حذفه في الوقت الحالي حتى يتم تصميم حل مناسب.
هذا الحل هو مشروع العاطفة. في هذا الوقت ، ليس مخصصًا لرمز الإنتاج. تم اختبار x64 بشكل جيد ومستقر ، حيث يمر stlkrn.sys خيارات التحقق الكاملة من برنامج التشغيل (بما في ذلك محاكاة الموارد المنخفضة العشوائية). تم اختبار معالجة الاستثناءات في الإرسال أو فوقها ، ولكن ليس في حالات الاستخدام العملي. x86 لم يتم اختباره. هناك وظائف تحت مساحة اسم jxy غير مكتملة/غير مستخدمة/لم يتم اختبارها. قد تختلف Milage الخاصة بك - أود مواصلة هذا العمل مع مرور الوقت ، إذا تم العثور على أي مشكلات/أخطاء ، فلا تتردد في فتح المشكلات ضد هذا الريبو.
يوفر هذا المشروع دعم STL في Windows kernel باستخدام أكبر قدر ممكن من منشأة STL. هناك حلول أخرى لاستخدام STL في تطوير النواة. سيوضح هذا القسم البدائل ، أولاً سألخص هذا العمل:
هذا المشروع:
new أو delete .atexit . أمر تهيئة CRT غير ضروري ، وينبغي أن يكون التهيئة والدموع واضحة . قد تقدم وظيفة atexit سباقات البيانات لرمز kernel ، لا يتم تنفيذ atexit .Bareflank Hypervisor:
يطبق Bareflank دعم تشغيل C ++ في Hypervisor. لديهم دعم كامل STL و CRT. هذا مشروع شامل يمكّن ميزات عدد كبير من المعيار في وضع kernel (بما في ذلك الاستثناءات). كما أفهم أن حلهم يجبر NonPagedPool على المخصصات العالمية new / delete . يجب أن أثني على Bareflank بتنفيذها ، إنه مدروس جيدًا ومنصة متقاطعة. ومع ذلك ، يبني تطبيق Windows من خلال Cygwin و "Shims" لدعم Kernel Windows. وبالمقارنة ، يهدف هذا المشروع إلى مراعاة نوافذ النوافذ. يتيح تحديد علامات التجمع وأنواعها (Paged vs غير المقيدة) وتأمل في تقليل "الحواف الحادة" المرتبطة باستخدام C ++ و STL في وضع kernel. كل ما قيل ، Bareflank مثير للإعجاب لما يفعل. للحصول على عرض تقديمي ممتاز حول دعم Bareflank لـ C ++ ، أوصي بشدة بمشاهدة عرض الدكتور ريان كوين في CPPCON 2016.
Win32Kernelstl:
يسمح لك مشروع Win32Kernelstl باستخدام وظائف STL مباشرة في kernel. يقوم المشروع بتنفيذ Global new / delete and Froject NonPagedPool ، ويقوم بتنفيذ دعم تهيئة CRT ، و Bugchecks عند طرح استثناء CPP. إنه لا يحاول القيام بالاسترخاء استثناء CPP. بسبب الافتراضات التي يجعلها أجدها غير عملية لأي حالات الاستخدام الخطيرة. الرمز واضح وموثق بشكل معقول ، أوصي بإعطاء هذا المشروع تصفحًا للتثقيف حول دعم C ++ في kernel. ملاحظة واحدة ، فإن رمز CRT في Win32KernelStl يقوم بتنفيذ atexit ولكن ضع في اعتبارك أنه لا يوجد مزامنة تنبعث من قبل المترجم هنا (على عكس وضع المستخدم). لذا فإن الثابت المحلي الذي يتطلب إدخال إدخال في قائمة atexit قد يتسبب في حدوث مصلح مزدوج أو مجاني.
برنامج التشغيل Plus:
ينفذ هذا المشروع منشأة C ++ اللازمة لسحب عدد من حلول C ++ في وضع kernel ( EASTL ، msgpack ، إلخ). يقوم برنامج التشغيل Plus Plus بتنفيذ تهيئة CRT والدعم العالمي new / delete (الذي يجبر NonPagedPool ). مرة أخرى ، هذا يتعارض مع أهداف هذا المشروع. ومع ذلك ، فإن هذا المشروع يمكّن الكثير من منشأة C ++ الرائعة للاستخدام في وضع kernel. إنها تقوم بإجراء تعديلات على حلول C ++ التي يسحبها إلى Shim لدعم حالات الاستخدام. يقوم Driver Plus Plus أيضًا بعمل الافتراض حول atexit كما ذكر سابقًا.
KTL - Dymok93
تقوم KTL (مكتبة قالب Windows kernel بواسطة Dymok93) بإعادة تصرف كمية جيدة من C ++ الحديثة وتطور بنشاط المزيد من الدعم للاستخدام في Kernel Windows. كما أن لديها دعمًا لـ RAII حول العديد من بدايات kernel ، ويوفر دعم ANSI_STRING و UNICODE_STRING الأصليين ، فهو يوفر بعض الأغلفة المفيدة لتسجيل عروض الاتصالات kernel ، والمزيد من ميزات الراحة حول نوافذ النوافذ. إنه ينفذ عالمي new / delete وله تعريف مسبق ( KTL_USING_NON_PAGED_NEW_AS_DEFAULT ) للتبديل بين الافتراضي أو غير المقيد ، وهو أمر جيد. ومع ذلك ، فإنه يستخدم علامة تجمع واحدة ( KTL_HEAP_TAG ). علاوة على ذلك ، لا تمكن قوالب المخصصات الحالية مطورًا من تحديد علامة تجمع ، لذا فإن استخدام هذه المكتبة كما هو-يؤدي إلى وضع علامة على جميع المخصصات بنفس علامة التجمع. ومع ذلك ، سيكون من المعقول تنفيذ مخصص مخصص يمكّن العلامات على المخصصات. لدى المكتبة دعم استثناء ، وإن كان X64 فقط. يعتمد دعم الاستثناء في KTL على Avakar مع التحسينات والإصلاحات. أثني على العمل هنا وأنا معجب بكمية التسهيلات الموجودة ، وهو معقول معقول ويتعرض للتطوير النشط. أرغب في استكشاف استخدامه أكثر في المستقبل ، وربما يتعاون على دعم استثناء أفضل لكل من stlkrn و KTL . إن إعادة تنفيذ وظائف STL ، ونقص دعم العلامات الأصلية ، والمخصصات العالمية تتعارض مع أيديولوجيات هذا المشروع.
KTL - Meesong:
تقوم KTL (مكتبة قالب Windows kernel by Meesong) بإعادة تهيئة كمية جيدة من وظائف C ++ الحديثة للاستخدام في Kernel Windows. كما أنه يقوم بتنفيذ Global new / delete ولكنه يقوم بعمل لائق في توفير منشأة لتحديد علامات التجمع وأنواعها حيثما أمكن ذلك. ومع ذلك ، هذا يعني أن المخصص العالمي قد يخفي تخصيصًا في مجموعة غير واضحة. علاوة على ذلك ، يحمل مخصصو القالب في هذا المشروع تكلفة نقطتين لكائن مخصص وموقد ، أنا قلق أيضًا من أن التحويل بين أنواع المخصصين قد يسمح بتوصيلات/تجمعات/حدة. بشكل عام ، أنا معجب بكمية المنشأة التي يتم تنفيذها هنا. إن إعادة تنفيذ وظائف STL والمخصصات العالمية تتعارض مع أيديولوجيات هذا المشروع.
kernel-bridge:
ينفذ kernel-bridge بعض التسهيلات الرائعة لتطوير النوافذ kernel. توفر المكتبة أغلفة للتسجيل لتراجعات Windows باستخدام كائنات C ++. أود أن أجد المزيد من الوقت للاستخدام والتحقيق في هذا الحل. انها تنفذ دعم CRT. وظيفة atexit التي تم تنفيذها ليست ديناميكية - فهي تستخدم صفيفًا ثابتًا ، إذا كان ينفد من الفتحات ، فإنه يفشل. الافتراضية new / delete القوات NonPagedPool . لا يتمتع بدعم استثناء كامل ، وسوف يتم ذلك إذا تم إلقاء استثناء CPP - لن يتم الاسترخاء على الكائنات على المكدس.
يستمد هذا المستودع من بعض الأعمال السابقة. اعتمادات لمؤلفيها.