diff options
Diffstat (limited to 'doc/html/nasmdoc9.html')
-rw-r--r-- | doc/html/nasmdoc9.html | 482 |
1 files changed, 0 insertions, 482 deletions
diff --git a/doc/html/nasmdoc9.html b/doc/html/nasmdoc9.html deleted file mode 100644 index 811af7c..0000000 --- a/doc/html/nasmdoc9.html +++ /dev/null @@ -1,482 +0,0 @@ -<html><head><title>NASM Manual</title></head> -<body><h1 align=center>The Netwide Assembler: NASM</h1> - -<p align=center><a href="nasmdo10.html">Next Chapter</a> | -<a href="nasmdoc8.html">Previous Chapter</a> | -<a href="nasmdoc0.html">Contents</a> | -<a href="nasmdoci.html">Index</a> -<h2><a name="chapter-9">Chapter 9: Writing 32-bit Code (Unix, Win32, DJGPP)</a></h2> -<p>This chapter attempts to cover some of the common issues involved when -writing 32-bit code, to run under Win32 or Unix, or to be linked with C -code generated by a Unix-style C compiler such as DJGPP. It covers how to -write assembly code to interface with 32-bit C routines, and how to write -position-independent code for shared libraries. -<p>Almost all 32-bit code, and in particular all code running under -<code><nobr>Win32</nobr></code>, <code><nobr>DJGPP</nobr></code> or any of -the PC Unix variants, runs in <em>flat</em> memory model. This means that -the segment registers and paging have already been set up to give you the -same 32-bit 4Gb address space no matter what segment you work relative to, -and that you should ignore all segment registers completely. When writing -flat-model application code, you never need to use a segment override or -modify any segment register, and the code-section addresses you pass to -<code><nobr>CALL</nobr></code> and <code><nobr>JMP</nobr></code> live in -the same address space as the data-section addresses you access your -variables by and the stack-section addresses you access local variables and -procedure parameters by. Every address is 32 bits long and contains only an -offset part. -<h3><a name="section-9.1">9.1 Interfacing to 32-bit C Programs</a></h3> -<p>A lot of the discussion in <a href="nasmdoc8.html#section-8.4">section -8.4</a>, about interfacing to 16-bit C programs, still applies when working -in 32 bits. The absence of memory models or segmentation worries simplifies -things a lot. -<h4><a name="section-9.1.1">9.1.1 External Symbol Names</a></h4> -<p>Most 32-bit C compilers share the convention used by 16-bit compilers, -that the names of all global symbols (functions or data) they define are -formed by prefixing an underscore to the name as it appears in the C -program. However, not all of them do: the <code><nobr>ELF</nobr></code> -specification states that C symbols do <em>not</em> have a leading -underscore on their assembly-language names. -<p>The older Linux <code><nobr>a.out</nobr></code> C compiler, all -<code><nobr>Win32</nobr></code> compilers, <code><nobr>DJGPP</nobr></code>, -and <code><nobr>NetBSD</nobr></code> and <code><nobr>FreeBSD</nobr></code>, -all use the leading underscore; for these compilers, the macros -<code><nobr>cextern</nobr></code> and <code><nobr>cglobal</nobr></code>, as -given in <a href="nasmdoc8.html#section-8.4.1">section 8.4.1</a>, will -still work. For <code><nobr>ELF</nobr></code>, though, the leading -underscore should not be used. -<p>See also <a href="nasmdoc2.html#section-2.1.27">section 2.1.27</a>. -<h4><a name="section-9.1.2">9.1.2 Function Definitions and Function Calls</a></h4> -<p>The C calling convention in 32-bit programs is as follows. In the -following description, the words <em>caller</em> and <em>callee</em> are -used to denote the function doing the calling and the function which gets -called. -<ul> -<li>The caller pushes the function's parameters on the stack, one after -another, in reverse order (right to left, so that the first argument -specified to the function is pushed last). -<li>The caller then executes a near <code><nobr>CALL</nobr></code> -instruction to pass control to the callee. -<li>The callee receives control, and typically (although this is not -actually necessary, in functions which do not need to access their -parameters) starts by saving the value of <code><nobr>ESP</nobr></code> in -<code><nobr>EBP</nobr></code> so as to be able to use -<code><nobr>EBP</nobr></code> as a base pointer to find its parameters on -the stack. However, the caller was probably doing this too, so part of the -calling convention states that <code><nobr>EBP</nobr></code> must be -preserved by any C function. Hence the callee, if it is going to set up -<code><nobr>EBP</nobr></code> as a frame pointer, must push the previous -value first. -<li>The callee may then access its parameters relative to -<code><nobr>EBP</nobr></code>. The doubleword at -<code><nobr>[EBP]</nobr></code> holds the previous value of -<code><nobr>EBP</nobr></code> as it was pushed; the next doubleword, at -<code><nobr>[EBP+4]</nobr></code>, holds the return address, pushed -implicitly by <code><nobr>CALL</nobr></code>. The parameters start after -that, at <code><nobr>[EBP+8]</nobr></code>. The leftmost parameter of the -function, since it was pushed last, is accessible at this offset from -<code><nobr>EBP</nobr></code>; the others follow, at successively greater -offsets. Thus, in a function such as <code><nobr>printf</nobr></code> which -takes a variable number of parameters, the pushing of the parameters in -reverse order means that the function knows where to find its first -parameter, which tells it the number and type of the remaining ones. -<li>The callee may also wish to decrease <code><nobr>ESP</nobr></code> -further, so as to allocate space on the stack for local variables, which -will then be accessible at negative offsets from -<code><nobr>EBP</nobr></code>. -<li>The callee, if it wishes to return a value to the caller, should leave -the value in <code><nobr>AL</nobr></code>, <code><nobr>AX</nobr></code> or -<code><nobr>EAX</nobr></code> depending on the size of the value. -Floating-point results are typically returned in -<code><nobr>ST0</nobr></code>. -<li>Once the callee has finished processing, it restores -<code><nobr>ESP</nobr></code> from <code><nobr>EBP</nobr></code> if it had -allocated local stack space, then pops the previous value of -<code><nobr>EBP</nobr></code>, and returns via -<code><nobr>RET</nobr></code> (equivalently, -<code><nobr>RETN</nobr></code>). -<li>When the caller regains control from the callee, the function -parameters are still on the stack, so it typically adds an immediate -constant to <code><nobr>ESP</nobr></code> to remove them (instead of -executing a number of slow <code><nobr>POP</nobr></code> instructions). -Thus, if a function is accidentally called with the wrong number of -parameters due to a prototype mismatch, the stack will still be returned to -a sensible state since the caller, which <em>knows</em> how many parameters -it pushed, does the removing. -</ul> -<p>There is an alternative calling convention used by Win32 programs for -Windows API calls, and also for functions called <em>by</em> the Windows -API such as window procedures: they follow what Microsoft calls the -<code><nobr>__stdcall</nobr></code> convention. This is slightly closer to -the Pascal convention, in that the callee clears the stack by passing a -parameter to the <code><nobr>RET</nobr></code> instruction. However, the -parameters are still pushed in right-to-left order. -<p>Thus, you would define a function in C style in the following way: -<p><pre> -global _myfunc - -_myfunc: - push ebp - mov ebp,esp - sub esp,0x40 ; 64 bytes of local stack space - mov ebx,[ebp+8] ; first parameter to function - - ; some more code - - leave ; mov esp,ebp / pop ebp - ret -</pre> -<p>At the other end of the process, to call a C function from your assembly -code, you would do something like this: -<p><pre> -extern _printf - - ; and then, further down... - - push dword [myint] ; one of my integer variables - push dword mystring ; pointer into my data segment - call _printf - add esp,byte 8 ; `byte' saves space - - ; then those data items... - -segment _DATA - -myint dd 1234 -mystring db 'This number -> %d <- should be 1234',10,0 -</pre> -<p>This piece of code is the assembly equivalent of the C code -<p><pre> - int myint = 1234; - printf("This number -> %d <- should be 1234\n", myint); -</pre> -<h4><a name="section-9.1.3">9.1.3 Accessing Data Items</a></h4> -<p>To get at the contents of C variables, or to declare variables which C -can access, you need only declare the names as -<code><nobr>GLOBAL</nobr></code> or <code><nobr>EXTERN</nobr></code>. -(Again, the names require leading underscores, as stated in -<a href="#section-9.1.1">section 9.1.1</a>.) Thus, a C variable declared as -<code><nobr>int i</nobr></code> can be accessed from assembler as -<p><pre> - extern _i - mov eax,[_i] -</pre> -<p>And to declare your own integer variable which C programs can access as -<code><nobr>extern int j</nobr></code>, you do this (making sure you are -assembling in the <code><nobr>_DATA</nobr></code> segment, if necessary): -<p><pre> - global _j -_j dd 0 -</pre> -<p>To access a C array, you need to know the size of the components of the -array. For example, <code><nobr>int</nobr></code> variables are four bytes -long, so if a C program declares an array as -<code><nobr>int a[10]</nobr></code>, you can access -<code><nobr>a[3]</nobr></code> by coding -<code><nobr>mov ax,[_a+12]</nobr></code>. (The byte offset 12 is obtained -by multiplying the desired array index, 3, by the size of the array -element, 4.) The sizes of the C base types in 32-bit compilers are: 1 for -<code><nobr>char</nobr></code>, 2 for <code><nobr>short</nobr></code>, 4 -for <code><nobr>int</nobr></code>, <code><nobr>long</nobr></code> and -<code><nobr>float</nobr></code>, and 8 for -<code><nobr>double</nobr></code>. Pointers, being 32-bit addresses, are -also 4 bytes long. -<p>To access a C data structure, you need to know the offset from the base -of the structure to the field you are interested in. You can either do this -by converting the C structure definition into a NASM structure definition -(using <code><nobr>STRUC</nobr></code>), or by calculating the one offset -and using just that. -<p>To do either of these, you should read your C compiler's manual to find -out how it organizes data structures. NASM gives no special alignment to -structure members in its own <code><nobr>STRUC</nobr></code> macro, so you -have to specify alignment yourself if the C compiler generates it. -Typically, you might find that a structure like -<p><pre> -struct { - char c; - int i; -} foo; -</pre> -<p>might be eight bytes long rather than five, since the -<code><nobr>int</nobr></code> field would be aligned to a four-byte -boundary. However, this sort of feature is sometimes a configurable option -in the C compiler, either using command-line options or -<code><nobr>#pragma</nobr></code> lines, so you have to find out how your -own compiler does it. -<h4><a name="section-9.1.4">9.1.4 <code><nobr>c32.mac</nobr></code>: Helper Macros for the 32-bit C Interface</a></h4> -<p>Included in the NASM archives, in the <code><nobr>misc</nobr></code> -directory, is a file <code><nobr>c32.mac</nobr></code> of macros. It -defines three macros: <code><nobr>proc</nobr></code>, -<code><nobr>arg</nobr></code> and <code><nobr>endproc</nobr></code>. These -are intended to be used for C-style procedure definitions, and they -automate a lot of the work involved in keeping track of the calling -convention. -<p>An example of an assembly function using the macro set is given here: -<p><pre> -proc _proc32 - -%$i arg -%$j arg - mov eax,[ebp + %$i] - mov ebx,[ebp + %$j] - add eax,[ebx] - -endproc -</pre> -<p>This defines <code><nobr>_proc32</nobr></code> to be a procedure taking -two arguments, the first (<code><nobr>i</nobr></code>) an integer and the -second (<code><nobr>j</nobr></code>) a pointer to an integer. It returns -<code><nobr>i + *j</nobr></code>. -<p>Note that the <code><nobr>arg</nobr></code> macro has an -<code><nobr>EQU</nobr></code> as the first line of its expansion, and since -the label before the macro call gets prepended to the first line of the -expanded macro, the <code><nobr>EQU</nobr></code> works, defining -<code><nobr>%$i</nobr></code> to be an offset from -<code><nobr>BP</nobr></code>. A context-local variable is used, local to -the context pushed by the <code><nobr>proc</nobr></code> macro and popped -by the <code><nobr>endproc</nobr></code> macro, so that the same argument -name can be used in later procedures. Of course, you don't <em>have</em> to -do that. -<p><code><nobr>arg</nobr></code> can take an optional parameter, giving the -size of the argument. If no size is given, 4 is assumed, since it is likely -that many function parameters will be of type <code><nobr>int</nobr></code> -or pointers. -<h3><a name="section-9.2">9.2 Writing NetBSD/FreeBSD/OpenBSD and Linux/ELF Shared Libraries</a></h3> -<p><code><nobr>ELF</nobr></code> replaced the older -<code><nobr>a.out</nobr></code> object file format under Linux because it -contains support for position-independent code (PIC), which makes writing -shared libraries much easier. NASM supports the -<code><nobr>ELF</nobr></code> position-independent code features, so you -can write Linux <code><nobr>ELF</nobr></code> shared libraries in NASM. -<p>NetBSD, and its close cousins FreeBSD and OpenBSD, take a different -approach by hacking PIC support into the <code><nobr>a.out</nobr></code> -format. NASM supports this as the <code><nobr>aoutb</nobr></code> output -format, so you can write BSD shared libraries in NASM too. -<p>The operating system loads a PIC shared library by memory-mapping the -library file at an arbitrarily chosen point in the address space of the -running process. The contents of the library's code section must therefore -not depend on where it is loaded in memory. -<p>Therefore, you cannot get at your variables by writing code like this: -<p><pre> - mov eax,[myvar] ; WRONG -</pre> -<p>Instead, the linker provides an area of memory called the <em>global -offset table</em>, or GOT; the GOT is situated at a constant distance from -your library's code, so if you can find out where your library is loaded -(which is typically done using a <code><nobr>CALL</nobr></code> and -<code><nobr>POP</nobr></code> combination), you can obtain the address of -the GOT, and you can then load the addresses of your variables out of -linker-generated entries in the GOT. -<p>The <em>data</em> section of a PIC shared library does not have these -restrictions: since the data section is writable, it has to be copied into -memory anyway rather than just paged in from the library file, so as long -as it's being copied it can be relocated too. So you can put ordinary types -of relocation in the data section without too much worry (but see -<a href="#section-9.2.4">section 9.2.4</a> for a caveat). -<h4><a name="section-9.2.1">9.2.1 Obtaining the Address of the GOT</a></h4> -<p>Each code module in your shared library should define the GOT as an -external symbol: -<p><pre> -extern _GLOBAL_OFFSET_TABLE_ ; in ELF -extern __GLOBAL_OFFSET_TABLE_ ; in BSD a.out -</pre> -<p>At the beginning of any function in your shared library which plans to -access your data or BSS sections, you must first calculate the address of -the GOT. This is typically done by writing the function in this form: -<p><pre> -func: push ebp - mov ebp,esp - push ebx - call .get_GOT -.get_GOT: - pop ebx - add ebx,_GLOBAL_OFFSET_TABLE_+$$-.get_GOT wrt ..gotpc - - ; the function body comes here - - mov ebx,[ebp-4] - mov esp,ebp - pop ebp - ret -</pre> -<p>(For BSD, again, the symbol -<code><nobr>_GLOBAL_OFFSET_TABLE</nobr></code> requires a second leading -underscore.) -<p>The first two lines of this function are simply the standard C prologue -to set up a stack frame, and the last three lines are standard C function -epilogue. The third line, and the fourth to last line, save and restore the -<code><nobr>EBX</nobr></code> register, because PIC shared libraries use -this register to store the address of the GOT. -<p>The interesting bit is the <code><nobr>CALL</nobr></code> instruction -and the following two lines. The <code><nobr>CALL</nobr></code> and -<code><nobr>POP</nobr></code> combination obtains the address of the label -<code><nobr>.get_GOT</nobr></code>, without having to know in advance where -the program was loaded (since the <code><nobr>CALL</nobr></code> -instruction is encoded relative to the current position). The -<code><nobr>ADD</nobr></code> instruction makes use of one of the special -PIC relocation types: GOTPC relocation. With the -<code><nobr>WRT ..gotpc</nobr></code> qualifier specified, the symbol -referenced (here <code><nobr>_GLOBAL_OFFSET_TABLE_</nobr></code>, the -special symbol assigned to the GOT) is given as an offset from the -beginning of the section. (Actually, <code><nobr>ELF</nobr></code> encodes -it as the offset from the operand field of the -<code><nobr>ADD</nobr></code> instruction, but NASM simplifies this -deliberately, so you do things the same way for both -<code><nobr>ELF</nobr></code> and <code><nobr>BSD</nobr></code>.) So the -instruction then <em>adds</em> the beginning of the section, to get the -real address of the GOT, and subtracts the value of -<code><nobr>.get_GOT</nobr></code> which it knows is in -<code><nobr>EBX</nobr></code>. Therefore, by the time that instruction has -finished, <code><nobr>EBX</nobr></code> contains the address of the GOT. -<p>If you didn't follow that, don't worry: it's never necessary to obtain -the address of the GOT by any other means, so you can put those three -instructions into a macro and safely ignore them: -<p><pre> -%macro get_GOT 0 - - call %%getgot - %%getgot: - pop ebx - add ebx,_GLOBAL_OFFSET_TABLE_+$$-%%getgot wrt ..gotpc - -%endmacro -</pre> -<h4><a name="section-9.2.2">9.2.2 Finding Your Local Data Items</a></h4> -<p>Having got the GOT, you can then use it to obtain the addresses of your -data items. Most variables will reside in the sections you have declared; -they can be accessed using the <code><nobr>..gotoff</nobr></code> special -<code><nobr>WRT</nobr></code> type. The way this works is like this: -<p><pre> - lea eax,[ebx+myvar wrt ..gotoff] -</pre> -<p>The expression <code><nobr>myvar wrt ..gotoff</nobr></code> is -calculated, when the shared library is linked, to be the offset to the -local variable <code><nobr>myvar</nobr></code> from the beginning of the -GOT. Therefore, adding it to <code><nobr>EBX</nobr></code> as above will -place the real address of <code><nobr>myvar</nobr></code> in -<code><nobr>EAX</nobr></code>. -<p>If you declare variables as <code><nobr>GLOBAL</nobr></code> without -specifying a size for them, they are shared between code modules in the -library, but do not get exported from the library to the program that -loaded it. They will still be in your ordinary data and BSS sections, so -you can access them in the same way as local variables, using the above -<code><nobr>..gotoff</nobr></code> mechanism. -<p>Note that due to a peculiarity of the way BSD -<code><nobr>a.out</nobr></code> format handles this relocation type, there -must be at least one non-local symbol in the same section as the address -you're trying to access. -<h4><a name="section-9.2.3">9.2.3 Finding External and Common Data Items</a></h4> -<p>If your library needs to get at an external variable (external to the -<em>library</em>, not just to one of the modules within it), you must use -the <code><nobr>..got</nobr></code> type to get at it. The -<code><nobr>..got</nobr></code> type, instead of giving you the offset from -the GOT base to the variable, gives you the offset from the GOT base to a -GOT <em>entry</em> containing the address of the variable. The linker will -set up this GOT entry when it builds the library, and the dynamic linker -will place the correct address in it at load time. So to obtain the address -of an external variable <code><nobr>extvar</nobr></code> in -<code><nobr>EAX</nobr></code>, you would code -<p><pre> - mov eax,[ebx+extvar wrt ..got] -</pre> -<p>This loads the address of <code><nobr>extvar</nobr></code> out of an -entry in the GOT. The linker, when it builds the shared library, collects -together every relocation of type <code><nobr>..got</nobr></code>, and -builds the GOT so as to ensure it has every necessary entry present. -<p>Common variables must also be accessed in this way. -<h4><a name="section-9.2.4">9.2.4 Exporting Symbols to the Library User</a></h4> -<p>If you want to export symbols to the user of the library, you have to -declare whether they are functions or data, and if they are data, you have -to give the size of the data item. This is because the dynamic linker has -to build procedure linkage table entries for any exported functions, and -also moves exported data items away from the library's data section in -which they were declared. -<p>So to export a function to users of the library, you must use -<p><pre> -global func:function ; declare it as a function - -func: push ebp - - ; etc. -</pre> -<p>And to export a data item such as an array, you would have to code -<p><pre> -global array:data array.end-array ; give the size too - -array: resd 128 -.end: -</pre> -<p>Be careful: If you export a variable to the library user, by declaring -it as <code><nobr>GLOBAL</nobr></code> and supplying a size, the variable -will end up living in the data section of the main program, rather than in -your library's data section, where you declared it. So you will have to -access your own global variable with the <code><nobr>..got</nobr></code> -mechanism rather than <code><nobr>..gotoff</nobr></code>, as if it were -external (which, effectively, it has become). -<p>Equally, if you need to store the address of an exported global in one -of your data sections, you can't do it by means of the standard sort of -code: -<p><pre> -dataptr: dd global_data_item ; WRONG -</pre> -<p>NASM will interpret this code as an ordinary relocation, in which -<code><nobr>global_data_item</nobr></code> is merely an offset from the -beginning of the <code><nobr>.data</nobr></code> section (or whatever); so -this reference will end up pointing at your data section instead of at the -exported global which resides elsewhere. -<p>Instead of the above code, then, you must write -<p><pre> -dataptr: dd global_data_item wrt ..sym -</pre> -<p>which makes use of the special <code><nobr>WRT</nobr></code> type -<code><nobr>..sym</nobr></code> to instruct NASM to search the symbol table -for a particular symbol at that address, rather than just relocating by -section base. -<p>Either method will work for functions: referring to one of your -functions by means of -<p><pre> -funcptr: dd my_function -</pre> -<p>will give the user the address of the code you wrote, whereas -<p><pre> -funcptr: dd my_function wrt .sym -</pre> -<p>will give the address of the procedure linkage table for the function, -which is where the calling program will <em>believe</em> the function -lives. Either address is a valid way to call the function. -<h4><a name="section-9.2.5">9.2.5 Calling Procedures Outside the Library</a></h4> -<p>Calling procedures outside your shared library has to be done by means -of a <em>procedure linkage table</em>, or PLT. The PLT is placed at a known -offset from where the library is loaded, so the library code can make calls -to the PLT in a position-independent way. Within the PLT there is code to -jump to offsets contained in the GOT, so function calls to other shared -libraries or to routines in the main program can be transparently passed -off to their real destinations. -<p>To call an external routine, you must use another special PIC relocation -type, <code><nobr>WRT ..plt</nobr></code>. This is much easier than the -GOT-based ones: you simply replace calls such as -<code><nobr>CALL printf</nobr></code> with the PLT-relative version -<code><nobr>CALL printf WRT ..plt</nobr></code>. -<h4><a name="section-9.2.6">9.2.6 Generating the Library File</a></h4> -<p>Having written some code modules and assembled them to -<code><nobr>.o</nobr></code> files, you then generate your shared library -with a command such as -<p><pre> -ld -shared -o library.so module1.o module2.o # for ELF -ld -Bshareable -o library.so module1.o module2.o # for BSD -</pre> -<p>For ELF, if your shared library is going to reside in system directories -such as <code><nobr>/usr/lib</nobr></code> or -<code><nobr>/lib</nobr></code>, it is usually worth using the -<code><nobr>-soname</nobr></code> flag to the linker, to store the final -library file name, with a version number, into the library: -<p><pre> -ld -shared -soname library.so.1 -o library.so.1.2 *.o -</pre> -<p>You would then copy <code><nobr>library.so.1.2</nobr></code> into the -library directory, and create <code><nobr>library.so.1</nobr></code> as a -symbolic link to it. -<p align=center><a href="nasmdo10.html">Next Chapter</a> | -<a href="nasmdoc8.html">Previous Chapter</a> | -<a href="nasmdoc0.html">Contents</a> | -<a href="nasmdoci.html">Index</a> -</body></html> |