📄 nasmdoc3.htm
字号:
<h3><a name="section-3.6">3.6 <code><nobr>SEG</nobr></code> and <code><nobr>WRT</nobr></code></a></h3><p>When writing large 16-bit programs, which must be split into multiplesegments, it is often necessary to be able to refer to the segment part ofthe address of a symbol. NASM supports the <code><nobr>SEG</nobr></code>operator to perform this function.<p>The <code><nobr>SEG</nobr></code> operator returns the<em>preferred</em> segment base of a symbol, defined as the segment baserelative to which the offset of the symbol makes sense. So the code<p><pre> mov ax,seg symbol mov es,ax mov bx,symbol</pre><p>will load <code><nobr>ES:BX</nobr></code> with a valid pointer to thesymbol <code><nobr>symbol</nobr></code>.<p>Things can be more complex than this: since 16-bit segments and groupsmay overlap, you might occasionally want to refer to some symbol using adifferent segment base from the preferred one. NASM lets you do this, bythe use of the <code><nobr>WRT</nobr></code> (With Reference To) keyword.So you can do things like<p><pre> mov ax,weird_seg ; weird_seg is a segment base mov es,ax mov bx,symbol wrt weird_seg</pre><p>to load <code><nobr>ES:BX</nobr></code> with a different, butfunctionally equivalent, pointer to the symbol<code><nobr>symbol</nobr></code>.<p>NASM supports far (inter-segment) calls and jumps by means of the syntax<code><nobr>call segment:offset</nobr></code>, where<code><nobr>segment</nobr></code> and <code><nobr>offset</nobr></code> bothrepresent immediate values. So to call a far procedure, you could codeeither of<p><pre> call (seg procedure):procedure call weird_seg:(procedure wrt weird_seg)</pre><p>(The parentheses are included for clarity, to show the intended parsingof the above instructions. They are not necessary in practice.)<p>NASM supports the syntax <code><nobr>call far procedure</nobr></code> asa synonym for the first of the above usages. <code><nobr>JMP</nobr></code>works identically to <code><nobr>CALL</nobr></code> in these examples.<p>To declare a far pointer to a data item in a data segment, you must code<p><pre> dw symbol, seg symbol</pre><p>NASM supports no convenient synonym for this, though you can alwaysinvent one using the macro processor.<h3><a name="section-3.7">3.7 <code><nobr>STRICT</nobr></code>: Inhibiting Optimization</a></h3><p>When assembling with the optimizer set to level 2 or higher (see<a href="nasmdoc2.html#section-2.1.16">section 2.1.16</a>), NASM will usesize specifiers (<code><nobr>BYTE</nobr></code>,<code><nobr>WORD</nobr></code>, <code><nobr>DWORD</nobr></code>,<code><nobr>QWORD</nobr></code>, or <code><nobr>TWORD</nobr></code>), butwill give them the smallest possible size. The keyword<code><nobr>STRICT</nobr></code> can be used to inhibit optimization andforce a particular operand to be emitted in the specified size. Forexample, with the optimizer on, and in <code><nobr>BITS 16</nobr></code>mode,<p><pre> push dword 33</pre><p>is encoded in three bytes <code><nobr>66 6A 21</nobr></code>, whereas<p><pre> push strict dword 33</pre><p>is encoded in six bytes, with a full dword immediate operand<code><nobr>66 68 21 00 00 00</nobr></code>.<p>With the optimizer off, the same code (six bytes) is generated whetherthe <code><nobr>STRICT</nobr></code> keyword was used or not.<h3><a name="section-3.8">3.8 Critical Expressions</a></h3><p>A limitation of NASM is that it is a two-pass assembler; unlike TASM andothers, it will always do exactly two assembly passes. Therefore it isunable to cope with source files that are complex enough to require threeor more passes.<p>The first pass is used to determine the size of all the assembled codeand data, so that the second pass, when generating all the code, knows allthe symbol addresses the code refers to. So one thing NASM can't handle iscode whose size depends on the value of a symbol declared after the code inquestion. For example,<p><pre> times (label-$) db 0 label: db 'Where am I?'</pre><p>The argument to <code><nobr>TIMES</nobr></code> in this case couldequally legally evaluate to anything at all; NASM will reject this examplebecause it cannot tell the size of the <code><nobr>TIMES</nobr></code> linewhen it first sees it. It will just as firmly reject the slightlyparadoxical code<p><pre> times (label-$+1) db 0 label: db 'NOW where am I?'</pre><p>in which <em>any</em> value for the <code><nobr>TIMES</nobr></code>argument is by definition wrong!<p>NASM rejects these examples by means of a concept called a <em>criticalexpression</em>, which is defined to be an expression whose value isrequired to be computable in the first pass, and which must thereforedepend only on symbols defined before it. The argument to the<code><nobr>TIMES</nobr></code> prefix is a critical expression; for thesame reason, the arguments to the <code><nobr>RESB</nobr></code> family ofpseudo-instructions are also critical expressions.<p>Critical expressions can crop up in other contexts as well: consider thefollowing code.<p><pre> mov ax,symbol1 symbol1 equ symbol2 symbol2:</pre><p>On the first pass, NASM cannot determine the value of<code><nobr>symbol1</nobr></code>, because<code><nobr>symbol1</nobr></code> is defined to be equal to<code><nobr>symbol2</nobr></code> which NASM hasn't seen yet. On the secondpass, therefore, when it encounters the line<code><nobr>mov ax,symbol1</nobr></code>, it is unable to generate the codefor it because it still doesn't know the value of<code><nobr>symbol1</nobr></code>. On the next line, it would see the<code><nobr>EQU</nobr></code> again and be able to determine the value of<code><nobr>symbol1</nobr></code>, but by then it would be too late.<p>NASM avoids this problem by defining the right-hand side of an<code><nobr>EQU</nobr></code> statement to be a critical expression, so thedefinition of <code><nobr>symbol1</nobr></code> would be rejected in thefirst pass.<p>There is a related issue involving forward references: consider thiscode fragment.<p><pre> mov eax,[ebx+offset] offset equ 10</pre><p>NASM, on pass one, must calculate the size of the instruction<code><nobr>mov eax,[ebx+offset]</nobr></code> without knowing the value of<code><nobr>offset</nobr></code>. It has no way of knowing that<code><nobr>offset</nobr></code> is small enough to fit into a one-byteoffset field and that it could therefore get away with generating a shorterform of the effective-address encoding; for all it knows, in pass one,<code><nobr>offset</nobr></code> could be a symbol in the code segment, andit might need the full four-byte form. So it is forced to compute the sizeof the instruction to accommodate a four-byte address part. In pass two,having made this decision, it is now forced to honour it and keep theinstruction large, so the code generated in this case is not as small as itcould have been. This problem can be solved by defining<code><nobr>offset</nobr></code> before using it, or by forcing byte sizein the effective address by coding<code><nobr>[byte ebx+offset]</nobr></code>.<p>Note that use of the <code><nobr>-On</nobr></code> switch (with n>=2)makes some of the above no longer true (see<a href="nasmdoc2.html#section-2.1.16">section 2.1.16</a>).<h3><a name="section-3.9">3.9 Local Labels</a></h3><p>NASM gives special treatment to symbols beginning with a period. A labelbeginning with a single period is treated as a <em>local</em> label, whichmeans that it is associated with the previous non-local label. So, forexample:<p><pre>label1 ; some code .loop ; some more code jne .loop ret label2 ; some code .loop ; some more code jne .loop ret</pre><p>In the above code fragment, each <code><nobr>JNE</nobr></code>instruction jumps to the line immediately before it, because the twodefinitions of <code><nobr>.loop</nobr></code> are kept separate by virtueof each being associated with the previous non-local label.<p>This form of local label handling is borrowed from the old Amigaassembler DevPac; however, NASM goes one step further, in allowing accessto local labels from other parts of the code. This is achieved by means of<em>defining</em> a local label in terms of the previous non-local label:the first definition of <code><nobr>.loop</nobr></code> above is reallydefining a symbol called <code><nobr>label1.loop</nobr></code>, and thesecond defines a symbol called <code><nobr>label2.loop</nobr></code>. So,if you really needed to, you could write<p><pre>label3 ; some more code ; and some more jmp label1.loop</pre><p>Sometimes it is useful - in a macro, for instance - to be able to definea label which can be referenced from anywhere but which doesn't interferewith the normal local-label mechanism. Such a label can't be non-localbecause it would interfere with subsequent definitions of, and referencesto, local labels; and it can't be local because the macro that defined itwouldn't know the label's full name. NASM therefore introduces a third typeof label, which is probably only useful in macro definitions: if a labelbegins with the special prefix <code><nobr>..@</nobr></code>, then it doesnothing to the local label mechanism. So you could code<p><pre>label1: ; a non-local label .local: ; this is really label1.local ..@foo: ; this is a special symbol label2: ; another non-local label .local: ; this is really label2.local jmp ..@foo ; this will jump three lines up</pre><p>NASM has the capacity to define other special symbols beginning with adouble period: for example, <code><nobr>..start</nobr></code> is used tospecify the entry point in the <code><nobr>obj</nobr></code> output format(see <a href="nasmdoc6.html#section-6.2.6">section 6.2.6</a>).<p align=center><a href="nasmdoc4.html">Next Chapter</a> |<a href="nasmdoc2.html">Previous Chapter</a> |<a href="nasmdoc0.html">Contents</a> |<a href="nasmdoci.html">Index</a></body></html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -