اللغات: English | 简体中文 | 繁體中文 | 日本語 | 한국어 | Français | Deutsch | Español | Italiano | Русский | العربية
← واجهة NeverC الثنائية للإضافات
الواجهة الخلفية أربع ترويسات وتسع وعشرون مرحلة. يصف PluginTarget.h هدفًا
والمسارات المارّة عبر توليد الشيفرة. ويبني PluginMC.h شيفرة الآلة ويراقبها.
أما تحليل التجميع وطباعته فيسكنان الترويسة نفسها. ويحوّل PluginObject.h ملفًا
قابلًا لإعادة التموضع إلى رسم بياني مُطبَّع والعكس.
معًا تتيح هذه الترويسات للإضافة أن تضيف هدفًا، أو تستبدل خطوة خفض واحدة أو كلها،
أو تراقب كل تعليمة لحظة إصدارها، أو تعرّف لهجة تجميع، أو تعيد كتابة ملف كائن
—عبر واجهة C ثنائية خالصة لا تكشف أبدًا عن MCInst أو MCSection أو
object::ObjectFile من LLVM.
#include "neverc/Plugin/PluginTarget.h"
#include "neverc/Plugin/PluginMC.h"
#include "neverc/Plugin/PluginObject.h" /* includes both of the above */| الواجهة | الجدول | الخانات | الغرض |
|---|---|---|---|
NEVERC_INTERFACE_TARGET_* |
NevercTargetAPI |
2 | RegisterTarget، RegisterCodeGenEdge |
NEVERC_INTERFACE_TARGET_ABI_* |
NevercTargetABIAPI |
1 | RegisterABI |
NEVERC_INTERFACE_CALLING_CONVENTION_* |
NevercCallingConventionAPI |
1 | RegisterCallingConvention |
NEVERC_INTERFACE_MC_* |
NevercMCAPI |
53 | قراءة MCUnit وتعديله؛ تسجيل المرمِّزات والمفكِّكات والواجهات الخلفية |
NEVERC_INTERFACE_MC_EMISSION_* |
NevercMCEmissionAPI |
7 | أحداث الإصدار ولقطات التخطيط |
NEVERC_INTERFACE_MC_PROVIDER_* |
NevercMCProviderAPI |
4 | استبدال MIR → MC |
NEVERC_INTERFACE_ASSEMBLY_PROVIDER_* |
NevercAssemblyProviderAPI |
8 | استبدال محلِّل التجميع أو طابعه |
NEVERC_INTERFACE_OBJECT_* |
NevercObjectAPI |
34 | قراءة ObjectGraph وتعديله |
NEVERC_INTERFACE_OBJECT_FORMAT_* |
NevercObjectFormatAPI |
1 | RegisterFormat |
NEVERC_INTERFACE_OBJECT_PHASE_* |
NevercObjectPhaseAPI |
2 | GetGraph، GetImage |
هذه هي القاعدة التي تحكم كل ما عداها هنا.
STABLE، ويمكن تثبيتها في الشيفرة بأمان: الواصفات المستقلة عن الهدف، ومعرِّفات المراحل، ومعرِّفات القطع الأثرية، وحاويتا MC وObjectGraph، ومعاملات الإخراج، وكل عقد رد نداء.
LOCKSTEP، وغير آمنة بلا فحص: مخططات الأكواد التشغيلية والسجلات والمعاملات وعمليات الإصلاح وإعادة التموضع واصطلاحات الاستدعاء الخاصة بالهدف. قيمها العددية لا تعني شيئًا إلا مقابل مراجعة مخطط واحدة بعينها.
في كل موضع تظهر فيه قيمة LOCKSTEP تظهر بجوارها بصمة مخطط. قارنها قبل قراءة القيمة:
if (!string_equal(Target.SchemaDigest, MY_COMPILED_SCHEMA_DIGEST))
return fail(NEVERC_STATUS_ABI_MISMATCH);كما ترفض NeverC المخطط غير المتطابق قبل استدعاء المزوِّد، فالفحص إذًا حزام وحمّالة معًا — لكن الإضافة التي تتخطاه وتقرأ كودًا تشغيليًا خامًا على أي حال ستُسيء تفسير التعليمات بصمت.
تسع وعشرون، في أربعة مجالات.
| المرحلة | السياسة |
|---|---|
neverc.codegen.ir_to_mir |
OBSERVABLE، INTERCEPTABLE، REPLACEABLE |
neverc.codegen.mir_to_mc |
OBSERVABLE، INTERCEPTABLE، REPLACEABLE |
neverc.codegen.coarse_lower |
OBSERVABLE، INTERCEPTABLE، REPLACEABLE |
neverc.codegen.product_verify |
OBSERVABLE، SEALED |
المراحل neverc.mc.encode وneverc.mc.decode وneverc.mc.layout هي
OBSERVABLE وINTERCEPTABLE وREPLACEABLE.
وneverc.mc.emission.pre_instruction هو حدث الإصدار الوحيد الذي يكون
REPLACEABLE أيضًا — وهناك تستبدل التعليمة. أما التسعة الأخرى (unit_begin
وunit_end وsection_change وpost_instruction وpost_encode وfixup
وrelaxation_round وpre_layout وpost_layout) فللمراقبة فقط.
neverc.assembly.parse وneverc.assembly.print قابلتان للاستبدال.
وneverc.assembly.final_verify وneverc.assembly.commit مختومتان.
neverc.object.probe وread وwrite وpre_write وpost_layout قابلة
للاستبدال؛ وneverc.object.post_write قابلة للاعتراض فقط؛ و
neverc.object.final_verify وneverc.object.commit مختومتان.
NevercTargetDescriptor هو أكبر واصف في هذه الواجهة الثنائية، لأنه يحمل كل ما
تحتاج الواجهتان الأمامية والخلفية إلى معرفته:
typedef struct NevercTargetDescriptor {
NevercABITableHeader Header;
NevercTargetID TargetID;
NevercStringView CanonicalName;
NevercStringArrayView Aliases;
NevercStructArrayView TripleMatchers; /* NevercTargetTripleMatcher[] */
NevercTargetABIID DefaultABI;
NevercCallingConventionID DefaultCallingConvention;
NevercInterfaceID MCSchemaID;
NevercInterfaceID DefaultObjectFormatID;
NevercTargetMachineDescriptor Machine;
NevercStructArrayView Macros; /* predefined macros */
NevercStructArrayView Builtins; /* target builtins + lowering */
NevercStructArrayView Registers; /* inline-asm register names */
NevercStructArrayView Constraints; /* inline-asm constraints */
NevercStringView Clobbers;
uint64_t Flags;
NevercTargetValidateCPUFn ValidateCPU;
NevercTargetCanonicalizeCPUFn CanonicalizeCPU;
NevercTargetListCPUsFn ListCPUs;
NevercTargetResolveFeaturesFn ResolveFeatures;
NevercCreateTargetMachineFn CreateTargetMachine;
NevercDestroyTargetMachineFn DestroyTargetMachine;
void *UserData;
NevercDestroyUserDataFn DestroyUserData;
} NevercTargetDescriptor;يقرِّر TripleMatchers متى يُختار الهدف: كل مُطابِق يسمّي معمارية ومورِّدًا ونظام
تشغيل وبيئة، إضافة إلى Priority يفضّ التعادل في مواجهة الأهداف المدمجة.
أما Machine فهو NevercTargetMachineDescriptor — تخطيط البيانات، ووحدات
المعالجة الافتراضية والمخصّصة للضبط، وجدول الميزات، وواجهات ABI واصطلاحات
الاستدعاء وصيغ الكائنات المدعومة، وفضاءات العناوين، ونموذجا إعادة التموضع والشيفرة
(بوصفهما قيمة افتراضية وقناع دعم معًا)، ونموذج الاستثناءات (NONE وDWARF
وSJLJ وSEH وWASM)، ونموذج فك الكدسة، وترتيب البايتات، وعرض
pointer/int/long/long long، ومحاذاة المكدس، وأقصى عرض ذرّي وشعاعي، ونوع
va_list، ومستويات التنفيذ (USER وKERNEL وHYPERVISOR وFIRMWARE)، ودعم
TLS.
وتحمل دوال الهدف المدمجة رد نداء الخفض الخاص بها، وهو يتلقّى بانيَ IR حيًّا:
static NevercStatus NEVERC_CALL
lower_builtin(void *UserData,
const NevercTargetBuiltinLoweringInvocation *In,
NevercIRValueHandle *OutResult) {
/* In->Core, In->Builder, In->Mutation, In->IRBuilder,
In->ResultType, In->Arguments, In->ArgumentCount */
return In->Builder->BuildCall(/* … */);
}تُصنِّف واجهة ABI تواقيع الدوال:
static NevercStatus NEVERC_CALL
classify(void *UserData, const NevercABIFunctionQuery *Query,
NevercABIArgumentClassification *ReturnValue,
NevercABIArgumentClassificationArray *Arguments) {
ReturnValue->Kind = NEVERC_ABI_ARGUMENT_DIRECT;
for (uint64_t I = 0; I != Arguments->Count; ++I) {
NevercABIArgumentClassification *A = &Arguments->Data[I];
A->Kind = NEVERC_ABI_ARGUMENT_INDIRECT;
A->Flags = NEVERC_ABI_ARGUMENT_BYVAL;
}
return neverc_status_ok();
}أنواع الوسائط هي DIRECT وEXTEND وINDIRECT وIGNORE وEXPAND
وINDIRECT_ALIASED وCOERCE_AND_EXPAND؛ والرايات هي BYVAL وREALIGN
وINREG وSRET_AFTER_THIS وCAN_BE_FLATTENED وSIGN_EXTEND
وPADDING_INREG. والإكراه إما NONE أو INTEGER أو FLOAT أو POINTER،
ويقدّم COERCE_AND_EXPAND مصفوفة من NevercABICoercionElement.
أما اصطلاح الاستدعاء فينزل مستوى أدنى ويخصّص المواقع الفعلية:
static NevercStatus NEVERC_CALL
plan(void *UserData, const NevercCallingConventionQuery *Query,
NevercCallingConventionPlan *Plan) {
/* Query->TargetID, ->CallingConventionID, ->SchemaDigest, ->Function */
/* Fill Plan->ReturnLocations and Plan->ArgumentLocations with
NevercCallingConventionLocation records: REGISTER or STACK,
ValueIndex, PieceOffset, Size, Alignment, RegisterNumber,
StackOffset, and INDIRECT / BYVAL flags. */
Plan->CalleeSavedRegisters = MySavedRegisters;
Plan->StackAlignment = 16;
return neverc_status_ok();
}الحقل Query->SchemaDigest قيمة LOCKSTEP — وRegisterNumber لا يعني شيئًا إلا
مقابل المخطط الذي يسمّيه. للاطلاع على المثال الكامل انظر
اصطلاحات استدعاء مخصّصة و
pluginsdk/examples/CustomCallConvPlugin.c.
يُختار المسار من NevercTargetKey القياسي: معرِّف الهدف، وأجزاء الثلاثية، ووحدة
المعالجة، ووحدة معالجة الضبط، والميزات، وABI، واصطلاح الاستدعاء، وصيغة الكائن،
ونموذج إعادة التموضع، ونموذج الشيفرة، ومستوى التنفيذ، وعرض المؤشر، وترتيب
البايتات، وبصمة المخطط. سجِّل الحوافّ التي تستطيع خدمتها:
NevercCodeGenEdgeDescriptor Edge = {0};
Edge.Header = /* … */;
Edge.EdgeID = MyEdgeID;
Edge.CanonicalName = SV("com.example.mir-to-mc");
Edge.TargetID = MyTargetID;
Edge.InputKind = NEVERC_CODEGEN_PRODUCT_MIR;
Edge.OutputKind = NEVERC_CODEGEN_PRODUCT_MC;
Edge.CompatibilityKey = SV("…");
Edge.ProviderID = SV("com.example.backend");
Target->RegisterCodeGenEdge(Target->Context, RegistrarContext, &Edge);أنواع النواتج هي IR وMIR وMC وASSEMBLY وOBJECT_GRAPH
وOBJECT_IMAGE وCUSTOM. والمسار الدقيق هو
IR → MIR → MC → ObjectGraph → ObjectImage.
وضبط NEVERC_CODEGEN_EDGE_COARSE مع تقديم CoarseLower يستبدل امتداد
IR → ObjectImage كله في خطوة واحدة:
static NevercStatus NEVERC_CALL
coarse_lower(void *UserData, NevercTaskHandle Task,
const NevercCodeGenRequest *Request,
NevercCodeGenProductCandidate *OutCandidate) {
/* Request->Target, ->Input, ->InputKind, ->OutputKind,
->OptimizationLevel, ->HasFinalIRProof */
OutCandidate->Kind = NEVERC_CODEGEN_PRODUCT_OBJECT_IMAGE;
OutCandidate->Artifact = MyImage;
OutCandidate->ProductID = MyProductID;
return neverc_status_ok();
}ومع ذلك يمرّ المسار الخشن عبر neverc.codegen.product_verify وعبر إيداع الإخراج
المعاملاتي. ويُستدعى VerifyProduct مصحوبًا بالالتزامات التي يتوقّع المُضيف أنك
أوفيت بها — VERIFY_FINAL_IR وVERIFY_TARGET_KEY وVERIFY_PRODUCT_KIND و
VERIFY_PRODUCT_ID وVERIFY_STRUCTURE — فلا يستطيع مزوِّد أن يتخطّى بوابةً
خِلسةً بسلوك طريق مختصر.
يحتوي MCUnit على أقسام ورموز وتعابير وشُذرات وتعليمات ومعاملات وعمليات إصلاح.
والقراءة تكرار بنمط first/next:
NevercMCUnitInfo Unit = {0};
Unit.Header = /* … */;
MC->GetUnitInfo(MC->Context, Task, UnitHandle, &Unit);
NevercMCSectionHandle Section;
MC->GetFirstSection(MC->Context, Task, UnitHandle, &Section);
while (!neverc_handle_is_null(Section)) {
NevercMCFragmentHandle Fragment;
MC->GetFirstFragment(MC->Context, Task, Section, &Fragment);
/* … */
MC->GetNextSection(MC->Context, Task, Section, &Section);
}والتعديل معاملاتي، كما في كل مكان آخر:
NevercMCMutationHandle Mutation;
MC->BeginMutation(MC->Context, Task, Unit, &Mutation);
MC->CreateSection(MC->Context, Task, Mutation, &SectionDescriptor, &Section);
MC->CreateSymbol(MC->Context, Task, Mutation, &SymbolDescriptor, &Symbol);
MC->AppendInstruction(MC->Context, Task, Mutation, Section, &Instruction);
Status = MC->CommitMutation(MC->Context, Task, Mutation);
if (Status.Code != NEVERC_STATUS_OK)
MC->AbandonMutation(MC->Context, Task, Mutation);المقابض محدودة بنطاق المهمة ومفحوصة بالأجيال، فالمقبض الآتي من تعديل مهجور يُرفَض بدل أن يُعاد استخدامه.
رايات الأقسام هي ALLOCATED وEXECUTABLE وWRITABLE وMERGEABLE وDEBUG.
وارتباطات الرموز هي LOCAL وGLOBAL وWEAK؛ وأنواعها NONE وFUNCTION
وOBJECT وSECTION وTLS؛ وتعريفاتها UNDEFINED وSECTION وABSOLUTE
وCOMMON. وتدعم التعابير العمليات الأحادية PLUS وMINUS وNOT، والثنائية
ADD وSUBTRACT وMULTIPLY وDIVIDE وAND وOR وXOR وSHIFT_LEFT
وSHIFT_RIGHT. ومرِّر NEVERC_MC_AUTOMATIC_OFFSET حيث تريد أن يضع المُضيف شيئًا
نيابة عنك.
ينشر RegisterSchema مخطط MC للهدف، ويحلّ GetSchemaToken /
GetSchemaTokenInfo الاسم إلى رمز LOCKSTEP والعكس.
يُبلِّغ تدفّق الإصدار عن عشرة أنواع من الأحداث بالترتيب — نوع لكل مرحلة
neverc.mc.emission.*. كما تحجز الواجهة الثنائية
NEVERC_MC_EMISSION_PRE_OBJECT_WRITE؛ وكتابة الكائن نفسها هي المرحلة المنفصلة
neverc.object.pre_write. اشترك بصفتك مراقبًا
واقرأ الحدث:
NevercMCEmissionEventInfo Event = {0};
Event.Header = /* … */;
Emission->GetEvent(Emission->Context, Frame, Frame->Input, &Event);
/* Event.Kind, Event.Flags */يخبرك Flags بأي أجزاء الحدث مُعبَّأة: HAS_SECTION وHAS_INSTRUCTION
وHAS_ENCODING وHAS_FIXUP وHAS_LAYOUT وCAN_REPLACE_INSTRUCTION. تحقَّق من
الراية قبل قراءة الحقل المقابل — فالحدث الذي لا ترميز له بعد لن يصير له ترميز
لمجرد أنك سألت.
وتعطي GetLayoutSection وGetLayoutFragment وGetLayoutSymbol و
GetLayoutFixup العناوين والأحجام متى ضُبطت HAS_LAYOUT.
وعند pre_instruction، وفقط حين تكون CAN_REPLACE_INSTRUCTION مضبوطة، يمكنك
الاستبدال:
const NevercMCAPI *MC;
NevercMCUnitHandle Unit;
NevercMCInstHandle Instruction;
Emission->BeginInstructionReplacement(Emission->Context, Frame, Continuation,
&MC, &Unit, &Instruction);
/* mutate Instruction through MC->BeginMutation / … / CommitMutation */
Emission->PublishInstructionReplacement(Emission->Context, Frame, Continuation,
&OutResult->Output);وpluginsdk/examples/MCObserverPlugin.c هو النسخة للقراءة فقط من هذا.
ثلاث عمليات تسجيل توسّع الواجهة الخلفية لشيفرة الآلة، وكلها مفهرسة بالهدف وببصمة المخطط:
MC->RegisterEncoder(MC->Context, RegistrarContext, &EncoderDescriptor);
MC->RegisterDecoder(MC->Context, RegistrarContext, &DecoderDescriptor);
MC->RegisterAsmBackend(MC->Context, RegistrarContext, &BackendDescriptor);يكتب المرمِّز عبر مصرف بدل أن يعيد مخزنًا مؤقتًا، وهو ما يُبقي الملكية في جانب المُضيف:
Sink->WriteBytes(Sink->Context, Bytes);
Sink->AddFixup(Sink->Context, &Fixup);ويُبلِّغ المفكِّك بواحدة من NEVERC_MC_DECODE_SUCCESS أو _SOFT_FAIL أو
_UNKNOWN أو _FAIL. وتصف أنواع الإصلاح نفسها عبر NevercMCFixupKindInfo
برايات PC_RELATIVE وSIGNED وRELAXABLE وTARGET.
وتملك الواجهة الخلفية للتجميع عملية الإرخاء. ويُصدر التخطيط بصمة إثبات، وأي تعديل بعد التخطيط يُبطل ذلك الإثبات ويفرض إعادة تخطيط قبل أن يمكن كتابة الكائن — وهو نفس نمط الفحص بالأجيال الذي يستعمله رسم الربط.
يستهلك مزوِّد التحليل بايتات المصدر وينشر MCUnit:
NevercAssemblyParseInputInfo In = {0};
In.Header = /* … */;
Asm->GetParseInput(Asm->Context, Frame, Frame->Input, &In);
NevercAssemblyTokenInfo Token = {0};
Asm->PeekSourceToken(Asm->Context, Frame, In.Source.Cursor, &Token);
Asm->AdvanceSourceToken(Asm->Context, Frame, In.Source.Cursor);
const NevercMCAPI *MC;
NevercMCUnitHandle Unit;
Asm->GetParseMCBuilder(Asm->Context, Frame, &MC, &Unit);
/* … build into Unit … */
Asm->PublishParsedMCUnit(Asm->Context, Frame, &Output);المصادر إما NEVERC_ASSEMBLY_SOURCE_BUFFER وإما
NEVERC_ASSEMBLY_SOURCE_RENDERED_TOKENS. والتجميع المعالَج مسبقًا (.S) يمرّ
أولًا عبر المعالج المسبق الأمامي المعتاد ويصل على هيئة رموز مُصيَّرة؛ أما التجميع
الخالص (.s) فيدخل المحلِّل مباشرة على هيئة مخزن مؤقت.
ويسير الطابع في الاتجاه المعاكس — GetPrintInput، ثم WritePrintOutput داخل
معاملة الإخراج المُقدَّمة، ثم PublishAssemblyOutput. والكتابة في أي مكان آخر غير
مدعومة: فتدقيق التحليل/الطباعة وبوابة إيداع المُضيف يعملان قبل أن تصير البايتات
مرئية، ولذا لا تترك الطباعة الفاشلة أي ملف ناقص وراءها.
يُطبِّع NevercObjectAPI الملف القابل لإعادة التموضع إلى أقسام ورموز وعمليات
إعادة تموضع وCOMDAT. وتغطي المحوّلات المدمجة ELF وCOFF وMach-O؛ ويضيف
RegisterFormat صيغة أخرى.
NevercObjectGraphInfo Info = {0};
Info.Header = /* … */;
Object->GetGraphInfo(Object->Context, Task, Graph, &Info);
/* Info.Target, .ObjectSchemaDigest, .Generation, .SectionCount,
.SymbolCount, .RelocationCount, .ComdatCount, .HasLayoutProof */
NevercObjectSymbolHandle Symbol;
Object->GetFirstSymbol(Object->Context, Task, Graph, &Symbol);
while (!neverc_handle_is_null(Symbol)) {
NevercObjectSymbolInfo SymInfo = {0};
SymInfo.Header = /* … */;
Object->GetSymbolInfo(Object->Context, Task, Symbol, &SymInfo);
Object->GetNextSymbol(Object->Context, Task, Symbol, &Symbol);
}ويتبع التعديل نمط الإنشاء/الاستبدال/النقل/المحو لأنواع الكيانات الأربعة جميعًا،
مُجهَّزًا داخل BeginMutation … CommitMutation / AbandonMutation.
رايات الأقسام هي ALLOCATED وEXECUTABLE وWRITABLE وMERGEABLE
وSTRINGS وTLS وDEBUG وUNWIND وDISCARDABLE وRETAIN. وأهداف إعادة
التموضع هي SYMBOL أو SECTION أو ABSOLUTE أو FORMAT_EXTENSION.
ولكل واصف ثلاثية ExtensionOwner / ExtensionVersion / Extension. وبهذا
تحتفظ الصيغة ببيانات لا حقل لها في الرسم المُطبَّع — إذ تسافر تلك البايتات مع
الكيان وتعود عند الكتابة، بدل أن تسقط في رحلة الذهاب والإياب.
NevercObjectFormatDescriptor Format = {0};
Format.Header = /* … */;
Format.FormatID = MyFormatID;
Format.CanonicalName = SV("com.example.myfmt");
Format.SupportedTargets = MyTargets;
Format.DefaultExtension = SV(".mof");
Format.Flags = NEVERC_OBJECT_FORMAT_CAN_PROBE |
NEVERC_OBJECT_FORMAT_CAN_READ |
NEVERC_OBJECT_FORMAT_CAN_WRITE;
Format.Probe = probe;
Format.Reader = read;
Format.Writer = write;
ObjectFormat->RegisterFormat(ObjectFormat->Context, RegistrarContext,
&Format);يُبلِّغ Probe عن Confidence من 0 إلى
NEVERC_OBJECT_PROBE_MAX_CONFIDENCE (1000)، وعن
NevercObjectArtifactKind الذي تعرَّف عليه (RELOCATABLE أو ARCHIVE أو
EXECUTABLE_IMAGE أو SHARED_IMAGE أو UNIVERSAL_BINARY)، وعن
ConsumedMinimum — أي كم بايتًا لزمه ليتيقّن، بحدّ أقصى
NEVERC_OBJECT_PROBE_MAX_CONSUMED_MINIMUM (65536). وتفوز أعلى ثقة.
ويُسلَّم Reader رسمًا وتعديلًا مفتوحًا فيملأهما. ويُسلَّم Writer الرسم وإثبات
تخطيطه والباني الثنائي المحدود.
- الاستكشاف وقراءة البايتات داخل ObjectGraph؛
- تشغيل معترضات الرسم
object.pre_write؛ - التخطيط ثم تشغيل
object.post_layout(إعادة التخطيط بعد أي تعديل)؛ - كتابة صورة مرشَّحة محدودة؛
- تشغيل المعترضات الثنائية
object.post_write؛ - تشغيل
object.final_verifyالمختوم وobject.commitالذرّي.
وتنتقل حالة الصورة CANDIDATE → VERIFIED → COMMITTED، أو ABORTED /
FAILED_PARTIAL.
ويتلقّى المراقبون جسورًا للقراءة فقط؛ وأي تعديل يُحاوَل من مراقب يُرفَض بـ
NEVERC_STATUS_POLICY_VIOLATION. ولا يحصل الكُتّاب ومعترضات ما بعد الكتابة إلا
على الباني المحدود NevercMutableBinaryAPI — Reserve وWrite وWriteAt
وTell وReadAt وInsert وAppend وResize. والفيضان أو فشل رد النداء أو
فشل التدقيق يُجهِض التجهيز، فلا يترك الفشل أبدًا نصف ملف على القرص.
وpluginsdk/examples/ObjectRewritePlugin.c مثال كامل على إعادة كتابة معاملاتية.
- قارن بصمة المخطط قبل استهلاك أي قيمة LOCKSTEP لكود تشغيلي أو سجل أو معامل أو إصلاح أو إعادة تموضع أو اصطلاح استدعاء.
- احفظ الحالة القابلة للتغيير في حالة process وsession وtask التي يوفّرها المُضيف.
- لا تُخزِّن مقابض المهام ولا العروض المُستعارة بعد عودة رد النداء.
- استدعِ استمرارية المُعترِض مرة واحدة على الأكثر، وفي خيط رد النداء.
- كل
BeginMutationيبلغ إيداعًا واحدًا بالضبط أو هجرًا واحدًا بالضبط. - أعِد التخطيط بعد تعديل
MCUnitأو ObjectGraph سبق تخطيطه؛ فإثبات التخطيط القديم بات قديمًا وسيرفضه المُضيف. - تحقَّق من
NevercMCEmissionEventInfo.Flagsقبل قراءة أي حقل حدث، ولا تستبدل تعليمة إلا حين تكونCAN_REPLACE_INSTRUCTIONمضبوطة. - لا تكتب الإخراج إلا عبر المعاملة أو مصرف البايتات المُقدَّم.
- أعِد
NevercStatusالأصلي عند الفشل ولا تنشر شيئًا ناقصًا. - أعلِن أضيق نموذجَي تزامن وإعادة دخول صادقين.
- المراحل
codegen.product_verifyوassembly.final_verifyوassembly.commitوobject.final_verifyوobject.commitمختومة. راقب فقط.
انظر PluginTarget.h وPluginMC.h وPluginObject.h و
Schema/PhaseSchema.json للإعلانات المِعيارية؛ وأنواع الكيانات والمعاملات
وعمليات الإصلاح والأقسام التي تستخدمها تأتي من Schema/MCSchema.json
وSchema/ObjectSchema.json، اللذين يولّدان Schema/PluginMCSchema.inc
وSchema/PluginObjectSchema.inc. وcoverage.json يربط كل مرحلة من هذه
المراحل المستقرة باختباراتها الإيجابية والسلبية والاستبدالية والمراقِبة
للقراءة فقط واختبارات البوابات المختومة.