日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

代码分析:NASM源码阅读笔记

發布時間:2025/6/15 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 代码分析:NASM源码阅读笔记 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
NASM源碼閱讀筆記
  NASM(Netwide Assembler)的使用文檔和代碼間的注釋相當齊全,這給閱讀源碼
提供了很大的方便。按作者的說法,這是一個模塊化的,可重用的x86匯編器,
而且能夠被嵌入進其它的程序中,比如做為一個高級語言編譯器的后端程序。下面
的文字希望能對大家有所幫助。錯誤之處,多多指正。:>

一、各模塊簡介:
? ?NASM按功能將匯編器的各個部分獨立為模塊,各個模塊之間并不進行直接的聯系。
? ?這種編程結構使得閱讀源代碼變得輕松起來,可以將各個模塊獨立出來分別閱讀。
? ?在源碼中的doc/internal.doc中有一個模塊間的結構圖:

? ? ? ? ? ? ? ? ?+--- preproc.c ----+
? ? ? ? ? ? ? ? ?| ? ? ? ? ? ? ? ? ?|
? ? ? ? ? ? ? ? ?+---- parser.c ----+
? ? ? ? ? ? ? ? ?| ? ? ? ?| ? ? ? ? |
? ? ? ? ? ? ? ? ?| ? ?? float .c ? ? ?|
? ? ? ? ? ? ? ? ?| ? ? ? ? ? ? ? ? ?|
? ? ? ? ? ? ? ? ?+--- assemble.c ---+
? ? ? ? ? ? ? ? ?| ? ? ? ?| ? ? ? ? |
? ? ? ?nasm.c ---+ ? ? insnsa.c ? ? +--- nasmlib.c
? ? ? ? ? ? ? ? ?| ? ? ? ? ? ? ? ? ?|
? ? ? ? ? ? ? ? ?+--- listing.c ----+
? ? ? ? ? ? ? ? ?| ? ? ? ? ? ? ? ? ?|
? ? ? ? ? ? ? ? ?+---- labels.c ----+
? ? ? ? ? ? ? ? ?| ? ? ? ? ? ? ? ? ?|
? ? ? ? ? ? ? ? ?+--- outform.c ----+
? ? ? ? ? ? ? ? ?| ? ? ? ? ? ? ? ? ?|
? ? ? ? ? ? ? ? ?+----- *out.c -----+
?圖中沒有出現的其它模塊有eval.c和float.c。eval.c是表達式求值模塊,用于
?preproc.c,parser.c和*out.c;float.c是浮點數常量存儲轉換模塊,用于parser.c。
?各模塊將需要導出的函數和數據結構的定義放入對應的頭文件中,以便被其它模塊調用。
? /* 需要注意的是許多函數指針或包含函數指針的結構以參數的形式在各模塊間傳遞,這種
? *間接性使得模塊之間的結構更加清晰。
?? */

  1 、強大的預處理器preproc.c:

    預處理部分是NASM中最復雜,也是代碼最多的模塊,有四千多行代碼。
    它使用自己的源碼掃描程序ppscan,支持名字相同但參數不同的宏,支持
    各個宏通過上下文相關堆棧來交換信息,支持宏內進行預處理循環等。
   ? (可參閱NASM使用文檔來了解預處理的功能和使用方法)

? ? ? ?preproc.c對外僅導出一個結構:
? ? ? ? ?? typedef ? struct ?{?
? ? ? ? ? ? ?? /*
? ? ? ? ? ? ? ?* Called at the start of a pass; given a file name, the number
? ? ? ? ? ? ? ?* of the pass, an error reporting function, an evaluator
? ? ? ? ? ? ? ?* function, and a listing generator to talk to.
? ? ? ? ? ? ? ? */
? ? ? ? ? ? ?? void ?(*reset) ( char ?*,? int , efunc, evalfunc, ListGen *);

? ? ? ? ? ? ?? /*
? ? ? ? ? ? ? ?* Called to fetch a line of preprocessed source. The line
? ? ? ? ? ? ? ?* returned has been malloc'ed, and so should be freed after
? ? ? ? ? ? ? ?* use.
? ? ? ? ? ? ? ? */
? ? ? ? ? ? ?? char ?*(*getline) ( void );

? ? ? ? ? ? ?? /*
? ? ? ? ? ? ? ?* Called at the end of a pass.
? ? ? ? ? ? ? ? */
? ? ? ? ? ? ?? void ?(*cleanup) ( int );
? ? ? ? ?? } Preproc;

? ? ? ? ? 其中reset用于初始化,cleanup用于預處理后的清理工作。
? ? ? ? ? 而函數名getline則是相對于主程序來說的。它對編譯器內嵌的宏和匯編源程序
? ? ? ? ? 從上至下進行處理,記錄遇到的宏信息,用實際的代碼和數據替換調用的宏,并
? ? ? ? ? 返回一行可以被下一個模塊(這里是parser.c)使用的“規范的”匯編代碼。
? ? ? ? ?? /* 預處理部分相對于主程序后面調用的模塊來說是透明的。 */

?? 2 、功能單一的解析模塊parser.c:
? ? ? ? ? ?按作者的說法,解析模塊的作用就是解析由`標號',`指令',`操作數'和`注釋'組成的
? ? ? ?“規范的”匯編代碼行,填充并返回這行代碼的insn結構:
? ? ? ? ?? typedef ? struct ?{? ? ? ? ? ? ? ? ? ? ? /* ?an instruction itself? */
? ? ? ? ? ? ?? char ?*label; ? ? ? ? ? ? ? ? ? ? /* ?the label defined, or NULL? */
? ? ? ? ? ? ?? int ?prefixes[MAXPREFIX]; ? ? ?? /* ?instruction prefixes, if any? */
? ? ? ? ? ? ?? int ?nprefix; ? ? ? ? ? ? ? ? ? ? /* ?number of entries in above? */
? ? ? ? ? ? ?? int ?opcode; ? ? ? ? ? ? ? ? ? ?? /* ?the opcode - not just the string? */
? ? ? ? ? ? ?? int ?condition; ? ? ? ? ? ? ? ? ? /* ?the condition code, if Jcc/SETcc? */
? ? ? ? ? ? ?? int ?operands; ? ? ? ? ? ? ? ? ?? /* ?how many operands? 0-3?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? * (more if db et al)? */
? ? ? ? ? ? ? operand oprs[ 3 ]; ? ? ? ? /* ?the operands, defined as above? */
? ? ? ? ? ? ? extop *eops; ? ? ? ? ? ? ? ? ? ? /* ?extended operands? */
? ? ? ? ? ? ?? int ?eops_float; ? ? ? ? ? ? ? ? /* ?true if DD and floating? */
? ? ? ? ? ? ?? long ?times; ? ? ? ? ? ? ? ? ? ?? /* ?repeat count (TIMES prefix)? */
? ? ? ? ? ? ?? int ?forw_ref; ? ? ? ? ? ? ? ? ?? /* ?is there a forward reference?? */
? ? ? ? ?? } insn;

? ? ? ? ? 該模塊導出三個函數:
? ? ? ? ?? void ?parser_global_info ( struct ?ofmt *output, loc_t *locp);
? ? ? ? ? insn *parse_line ( int ?pass,? char ?*buffer, insn *result,
? ? ? ? ? ? ? ? ? ? ? ? ?efunc error, evalfunc evaluate, ldfunc ldef);
? ? ? ? ?? void ?cleanup_insn (insn *instruction);

? ? ? ? ? 其中parser_global_info用于解析前的初始化工作(這里是初始化輸出的文件格式和
? ? ? ? ? 當前行所在的位置,在定義標號時需要用到)。cleanup_insn用于解析后的清理工作。

? ? ? ? ? 而parse_line的功能就是按照上面提到的`標號',`指令',`操作數'和`注釋'的
? ? ? 順序對buffer里的代碼進行解析,并對相應部分的合法性做一些檢查,比如檢查指令的前綴是
? ? ? 不是超過了所能允許的最大值,操作數是否為內存地址,代碼中是否含有一個向前的引用等。
? ? ? 它還提供了對偽指令DB,DD,RESB,RESD,INCBIN等的支持。

?? 3 、代碼生成器assemble.c:

? ? ? ? 當parser.c填充好insn結構后,assemble.c就按照Intel機器碼規則生成實際的
? ? ?機器碼,并傳給out*.c來生成具體格式的目標文件。

? ? ? ? ? 它導出兩個函數:
? ? ? ? ?? long ?insn_size ( long ?segment,? long ?offset,? int ?bits,? unsigned ? long ?cpu,
? ? ? ? ? ? ? ? ? ? ? ?insn *instruction, efunc error);
? ? ? ? ?? long ?assemble ( long ?segment,? long ?offset,? int ?bits,? unsigned ? long ?cpu,
? ? ? ? ? ? ? ? ? ? ? insn *instruction,? struct ?ofmt *output, efunc error,
? ? ? ? ? ? ? ? ? ? ? ListGen *listgen);
? ? ? ? ? 其中insn_size一般用在第一遍分析源碼時,用于確定某一行代碼在實際目標文件中所需的
? ? ? 空間,而assemble則一般用在第二遍分析源碼時,它轉化insn結構中的指令為實際的機器碼,
? ? ? 并輸出到out*.c中以生成具體格式的目標文件。

?? 4 、簡單的表達式求值模塊eval.c:
?     eval.c用于計算并返回代碼中表達式的值,其中運算符||,^^,&&等用于條件匯編%if類指令
?   的表達式中,返回真或假,|,^,&,<<,+,*,/等用于對常量值進行運算,SEG,WRT等則用于得到
? ? ? 程序中段(或節)實際的基址和偏移。
? ? ? ? ? eval.c的功能比較簡單,不能像MASM那樣處理類似(eax !=? 0 )這樣的表達式。 (后記1)
?     eval.c利用標準的scan程序掃描表達式緩沖區,找出存在的運算符進行運算,并將
?   處理后的值存入expr結構中:
? ? ? ? ? ? /*
? ? ? ? ? ? * Expression-evaluator datatype. Expressions, within the
? ? ? ? ? ? * evaluator, are stored as an array of these beasts, terminated by
? ? ? ? ? ? * a record with type== 0. ?Mostly, it's a vector type: each type
? ? ? ? ? ? * denotes some kind of a component, and the value denotes the
? ? ? ? ? ? * multiple of that component present in the expression. The
? ? ? ? ? ? * exception is the WRT type, whose `value' field denotes the
? ? ? ? ? ? * segment to which the expression is relative. These segments will
? ? ? ? ? ? * be segment-base types, i.e. either odd segment values or SEG_ABS
? ? ? ? ? ? * types. So it is still valid to assume that anything with a
? ? ? ? ? ? * `value' field of zero is insignificant.
? ? ? ? ? ?? */
? ? ? ? ? ? typedef ? struct ?{?
? ? ? ? ? ? ? ? long ?type; ? ? ? ? ? ? ? ? ? ? ? ? ? ?? /* ?a register, or EXPR_xxx? */
? ? ? ? ? ? ? ? long ?value; ? ? ? ? ? ? ? ? ? ? ? ? ? ? /* ?must be >=? 32 ?bits? */
? ? ? ? ? ? } expr;
? ? ? ? ? ?值得注意的是eval.c只在第一遍分析源碼時處理運算符||,^^,&&等,因為它們只在
? ? ? ?預處理表達式中才可能出現。

? ? 5. ?標號處理器label.c:
? ? ? ? ? ?NASM的標號分局部標號和全局標號兩種(外部標號可看作是在另一個源程序中的全局標號)。
? ? ? ? ? ?局部標號名最終將由兩部分組成: "上一個全局標號名+局部標號名"
? ? ? ? ? ?全局標號名最終將由三部分組成: "lprefix+全局標號名+lpostfix" 。其中lprefix和lpostfix
? ? ? ?都是可選的,它們分別用于在所有的全局標號名的前面和后面添加字符串。比如在編譯時指定選項
? ? ? ?--prefix_ 將會在所在的全局標號名前加下劃線,這就會和在C中生成標號的情況差不多。
? ? ? ? ? ?最終lable.c會將標號的相關信息傳給對應的out*.c來生成目標文件中的符號。

? ? ? ? ? ?這個模塊導出以下數據和函數:
? ? ? ? ? ? ? ? extern ? char ?lprefix[PREFIX_MAX];
? ? ? ? ? ? ? ? extern ? char ?lpostfix[PREFIX_MAX];

? ? ? ? ? ? ? ? int ?lookup_label ( char ?*label,? long ?*segment,? long ?*offset);
? ? ? ? ? ? ? ? int ?is_extern ( char ?*label);
? ? ? ? ? ? ? ? void ?define_label ( char ?*label,? long ?segment,? long ?offset,? char ?*special,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? int ?is_norm,? int ?isextrn,? struct ?ofmt *ofmt, efunc error);
? ? ? ? ? ? ? ? void ?redefine_label ( char ?*label,? long ?segment,? long ?offset,? char ?*special,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? int ?is_norm,? int ?isextrn,? struct ?ofmt *ofmt, efunc error);
? ? ? ? ? ? ? ? void ?define_common ( char ?*label,? long ?segment,? long ?size,? char ?*special,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct ?ofmt *ofmt, efunc error);
? ? ? ? ? ? ? ? void ?declare_as_global ( char ?*label,? char ?*special, efunc error);
? ? ? ? ? ? ? ? int ?init_labels ( void );
? ? ? ? ? ? ? ? void ?cleanup_labels ( void );

? ? ? ?  函數init_labels和cleanup_labels分別用于內部數據的初始化和清理工作。
? ? ? ?  函數lookup_label用于查找存在的標號并返回對應的段和偏移的值。
? ? ? ?  函數define_label用于定義標號并將信息傳遞給相應的out*.c來生成目標文件中的符號。
? ? ? ? ? ?函數redefine_label用于檢查標號是否存在定位錯誤并對其進行修正(按作者的說法,雖然大多
? ? ? ? ? ?數的匯編器都存在這個功能,但在這里好像并不能起到什么作用)。

? ? 6. ?列表文件生成模塊listing.c:
? ? ? ? ? ?list.c用于生成列表文件。列表文件的格式如下:
? ? ? ?    列表文件的行號 代碼在目標文件中的偏移 <列表嵌套層數> 源代碼行或宏展開后的代碼

? ? ? ? ? ?其中的列表嵌套層數用于INCBIN,TIMES,INCLUDE和MACRO等偽指令,用于表示這些指令展開后在
? ? ? ?代碼中嵌套的層數。在實際生成的列表文件中不對TIMES指令和指定了.nolist的宏進行展開操作。

? ? ? ?  list.c對外導出如下結構:
? ? ? ? ? ? ? ?ListGen nasmlist = {?
? ? ? ? ? ? ? ? ? ?list_init,
? ? ? ? ? ? ? ? ? ?list_cleanup,
? ? ? ? ? ? ? ? ? ?list_output,
? ? ? ? ? ? ? ? ? ?list_line,
? ? ? ? ? ? ? ? ? ?list_uplevel,
? ? ? ? ? ? ? ? ? ?list_downlevel
? ? ? ? ? ? ? ? };
? ? ? ?  其中list_init和list_cleanup分別用于模塊內部數據的初始化和清理操作。
? ? ? ?  list_output用于生成列表文件格式中的的前兩部分,list_line用于生成列表文件格式中的
? ? ? ?后兩部分。list_upleve和list_downlevel被其它模塊調用,以更新list.c中的列表嵌套層數。
? ? ? ?值得注意的是源碼中的數據結構MacroInhibit目前在模塊中并沒有什么實際的作用,而且list.c
? ? ? ?也沒有對傳入的參數進行充分的處理。按作者的說法,這些函數實現并沒有經過很好的考慮,
? ? ? ?它們只是因為 "差不多能夠工作" ,所以才被保留至今。

? ? 7. ?浮點數轉換模塊float.c:
? ? ? ? ? ? float .c模塊導出一個函數float_const:
? ? ? ? ? ? ? ? int ?float_const ( char ?*number,? long ?sign,? unsigned ? char ?*result,? int ?bytes,
? ? ? ? ? ? ? ? efunc error);
? ? ? ? ? ?這個函數負責將指令DD, DQ和DT后的浮點數常量轉換為Intel機器內部的數據表達形式。
? ? ? ? ? ? float .c能識別的浮點數格式如下:
? ? ? ? ? ? ? ?dd ? ? 1.2 ?? ? ? ? ? ? ? ? ? ? ; an easy one
? ? ? ? ? ? ? ?dq ? ? 1.e10 ?? ? ? ? ? ? ? ? ? ;? 10 , 0 00 , 0 00 , 0 00
? ? ? ? ? ? ? ?dq ? ? 1.e+10 ?? ? ? ? ? ? ? ? ?; synonymous with? 1.e10
? ? ? ? ? ? ? ?dq ? ? 1.e-10 ?? ? ? ? ? ? ? ? ?;? 0.000 ? 0 00 ? 0 00 ? 1
? ? ? ? ? ? ? ?dt ? ? 3.141592653589793238462 ?; pi
? ? ? ? ? ?需要注意的是NASM不提供浮點數的表達式求值運算,這是因為NASM認為不能保證所有
? ? ? ?存在ANSI C編譯器的的系統都提供浮點數運算的庫函數,而自己實現又有點得不償失。

? ? 8. 指令模板集模塊insnsa.c:
? ? ? ? ? ?NASM的CVS庫中有三個與該模塊有關的文件:insns.h(指令模板結構定義和其它常量定義),
? ? ? ?insns.dat(NASM能識別的Intel指令集信息表),insns.pl(用于從insns.dat中生成insnsa.c,
? ? ? ?insnsd.c, insnsi.h, insnsn.c等文件的Perl腳本)。
? ? ? ? ? 在insns.pl生成的四個文件中,insnsa.c和insnd.c是C格式的指令集信息表,分別用于
? ? ? ?assemble.c和ndisasm.c。insnsi.h是指令集名字的枚舉表,insnsn.c是指令集名字的字符串表,
? ? ? ?這兩個文件用在掃描(nasmlib.c)和反匯編(ndisasm.c)中。

? ? 9. ?為其它模塊提供支持的nasmlib.c:
? ? ? ? ? ?nasmlib.c提供如下函數:
? ? ? ? ? ? ?·具有報錯和記錄功能的內存分配和釋放函數;
? ? ? ? ? ? ?·字符串和數字間的轉換和賦值函數;
? ? ? ? ? ? ?·對動態分配的隨機存儲數組(RAA)和順序存儲數組(SAA)進行管理的函數;
? ? ? ? ? ? ?·一個標準的源碼掃描函數;
? ? ? ? ? ? ?·表達式處理的庫函數;
? ? ? ? ? ? ?·為目標文件自動添加擴展名的函數;
? ? ? ? ? ? ?·對源碼和目標文件提供支持的其它函數。

? ? 10. ?目標格式文件輸出模塊output\*out.c和對其進行管理的模塊outform.c:
? ? ? ? ? ? ? ?output目錄下的*out.c是NASM所能輸出的目標格式文件的源代碼實現。每一個輸出模塊
? ? ? ? ? ?一般只導出一個ofmt形式的數據結構(ofmt數據結構的定義可參見nasm.h文件)。
? ? ? ? ? ? ? ?out*.c還提供了對特定格式的附加指令支持。比如如果在生成OBJ格式時想導入其它DLL的
? ? ? ? ? ?函數,可以使用import指令,如下將導入wsock32.dll中的函數WSAStartup:
? ? ? ? ? ? ? ?import WSAStartup wsock32.dll

? ? ? ? ? ? ? ?outform.c提供了對上述模塊進行查找,列舉和注冊的功能。

二、流程簡介:

? ?主程序nasm.c的流程如下:

? ? ? ?( 1 )初始化需要的數據結構,注冊編譯器支持的目標文件格式。
? ? ? ?( 2 )使用內部函數parse_cmdline解析命令行參數,設置對應的參數值或輸出相應的幫助信息后退出。
? ? ? ?( 3 )如果生成的目標格式中含有附加的標準宏,調用預處理中的函數對其進行注冊。
? ? ? ?( 4 )調用函數parser_global_info和eval_global_info分別初始化parser.c和eval.c。

? ? ? ?( 5 )根據變量operating_mode的值判斷操作模式,默認為op_normal。
? ? ? ? ? ? 1. 如果operating_mode為op_depend(編譯時指定了參數-M),則對外輸出makefile格式的文件依賴關系;
? ? ? ? ? ? 2. 如果operating_mode為op_preprocess(編譯時指定了參數-e),則只對源代碼進行預處理操作,并添加相應的
? ? ? ? ? ? ?行號信息,然后輸出到目標文件或標準輸出( stdout );
? ? ? ? ? ? 3. 如果operating_mode為op_normal,則先調用函數init_labels和ofmt->init分別初始化label.c和out*.c,
? ? ? ? ? ? ?然后調用函數assemble_file對源文件進行編譯處理。

? ? ? ?( 6 )釋放掉程序動態分配的內存(RAA和SAA),調用函數eval_cleanup和nasmlib_cleanup進行相應模塊的清理工作。
? ? ? ? ? 然后根據變量terminate_after_phase的值設置程序返回值并結束運行。

? ?其中的函數assemble_file負責了最主要的工作,它接收源程序文件名,并調用各個模塊對源程序進行預處理,
? ?解析,編譯,生成指定目標格式文件等操作。
? ? ? ?assemble_file函數流程如下:

? ? ? ?( 1 )初始化目標文件格式中的段(節)和偏移值,初始化預處理模塊,設置當前掃描次數。
? ? ? ?( 2 )調用預處理模塊中的函數preproc->getline()返回一行可以被解析使用的“標準”匯編代碼,并增加當前行數。

? ? ? ?( 3 )調用函數getkw(line,&value)來判斷當前行格式是否為[directive value]并返回directive和value相應的值。
? ? ? ? ? 這里的directive是指NASM自己的一些偽指令,例如SECTION,EXTERN,GLOBAL等。若上述格式getkw無法識別,
? ? ? ? ? 則調用ofmt->directive (line+ 1 , value,? 1 )來判斷是否為目標文件格式的附加指令。
? ? ? ?( 4 )若當前行不是上述格式,則調用標準的解析函數parse_line解析當前行。
? ? ? ?( 5 )記錄或處理當前行指令中的向前引用。
? ? ? ?( 6 )處理EQU指令,并只在第二次解析時才處理標號前綴為 ".." 的特殊EQU指令。

? ? ? ?( 7 )調用編譯模塊進行處理。第一次掃描源碼時調用insn_size,并對偽指令RESB,DB等調用
? ? ? ? ? 函數ofmt->current_dfmt->debug_typevalue(typeinfo)來設置調試信息;第二次掃描時則直接調用assemble來
? ? ? ? ? 生成目標代碼。
? ? ? ?( 8 )調用函數preproc->cleanup()和nasmlist.cleanup()進行掃描后的清理工作。
? ? ? ?( 9 )若掃描次數小于 2 ,則跳轉到( 1 )進行下一遍掃描。


三、閱讀小結
? ? ? ?通過對NASM源碼的閱讀,我認為它有以下優點:
? ? ? ?( 1 )采用了模塊化的開發模式,各個模塊間相對獨立,便于擴展功能和修改,也利于被其它程序使用。
? ? ? ?( 2 )預處理功能比較強大,對宏的命名和參數量要求比較靈活。
? ? ? ?( 3 )使用了通過HASH運算將數組和鏈表結合在一起的數據結構,提高了查找效率。
? ? ? ?( 4 )使用文檔和代碼間的注釋相當齊全,便于他人閱讀。

? ? ? ?同時,NASM也存在以下問題:
? ? ? ?( 1 )各模塊間無法進行相互間的通信。這就導致模塊間存在一些重復性代碼。另外在模塊內部也有少許重復代碼。
? ? ? ?( 2 )listing.c模塊和eval.c模塊功能簡單,特別是listing.c目前尚不完善。
? ? ? ?( 3 )實質上的架構只提供了兩遍的源碼掃描,這就導致它對表達式的要求比較嚴格,不能處理需要多遍掃描才能
? ? ? ?  完成的表達式,這方面的內容可參閱NASM的幫助文檔中的Critical Expressions一節。

? ? ? ?( 4 )在可輸出的目標格式文件中,只有少數幾個支持生成含有調試信息的目標文件。

總結

以上是生活随笔為你收集整理的代码分析:NASM源码阅读笔记的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。