aboutsummaryrefslogtreecommitdiff
path: root/documentation/content/en/books/developers-handbook/x86/_index.po
diff options
context:
space:
mode:
Diffstat (limited to 'documentation/content/en/books/developers-handbook/x86/_index.po')
-rw-r--r--documentation/content/en/books/developers-handbook/x86/_index.po8103
1 files changed, 8103 insertions, 0 deletions
diff --git a/documentation/content/en/books/developers-handbook/x86/_index.po b/documentation/content/en/books/developers-handbook/x86/_index.po
new file mode 100644
index 0000000000..23cfaca453
--- /dev/null
+++ b/documentation/content/en/books/developers-handbook/x86/_index.po
@@ -0,0 +1,8103 @@
+# SOME DESCRIPTIVE TITLE
+# Copyright (C) YEAR The FreeBSD Project
+# This file is distributed under the same license as the FreeBSD Documentation package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: FreeBSD Documentation VERSION\n"
+"POT-Creation-Date: 2024-01-17 20:34-0300\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. type: Title =
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:14
+#, no-wrap
+msgid "x86 Assembly Language Programming"
+msgstr ""
+
+#. type: YAML Front Matter: title
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1
+#, no-wrap
+msgid "Chapter 11. x86 Assembly Language Programming"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:52
+msgid "_This chapter was written by {stanislav}._"
+msgstr ""
+
+#. type: Title ==
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:54
+#, no-wrap
+msgid "Synopsis"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:58
+msgid ""
+"Assembly language programming under UNIX(R) is highly undocumented. It is "
+"generally assumed that no one would ever want to use it because various "
+"UNIX(R) systems run on different microprocessors, so everything should be "
+"written in C for portability."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:62
+msgid ""
+"In reality, C portability is quite a myth. Even C programs need to be "
+"modified when ported from one UNIX(R) to another, regardless of what "
+"processor each runs on. Typically, such a program is full of conditional "
+"statements depending on the system it is compiled for."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:64
+msgid ""
+"Even if we believe that all of UNIX(R) software should be written in C, or "
+"some other high-level language, we still need assembly language programmers: "
+"Who else would write the section of C library that accesses the kernel?"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:66
+msgid ""
+"In this chapter I will attempt to show you how you can use assembly language "
+"writing UNIX(R) programs, specifically under FreeBSD."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:71
+msgid ""
+"This chapter does not explain the basics of assembly language. There are "
+"enough resources about that (for a complete online course in assembly "
+"language, see Randall Hyde's http://webster.cs.ucr.edu/[Art of Assembly "
+"Language]; or if you prefer a printed book, take a look at Jeff Duntemann's "
+"Assembly Language Step-by-Step (ISBN: 0471375233). However, once the "
+"chapter is finished, any assembly language programmer will be able to write "
+"programs for FreeBSD quickly and efficiently."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:73
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4310
+msgid "Copyright (R) 2000-2001 G. Adam Stanislav. All rights reserved."
+msgstr ""
+
+#. type: Title ==
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:75
+#, no-wrap
+msgid "The Tools"
+msgstr ""
+
+#. type: Title ===
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:78
+#, no-wrap
+msgid "The Assembler"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:81
+msgid ""
+"The most important tool for assembly language programming is the assembler, "
+"the software that converts assembly language code into machine language."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:84
+msgid ""
+"Three very different assemblers are available for FreeBSD. Both man:llvm-"
+"as[1] (included in package:devel/llvm[]) and man:as[1] (included in package:"
+"devel/binutils[]) use the traditional UNIX(R) assembly language syntax."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:87
+msgid ""
+"On the other hand, man:nasm[1] (installed through package:devel/nasm[]) uses "
+"the Intel syntax. Its main advantage is that it can assemble code for many "
+"operating systems."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:90
+msgid ""
+"This chapter uses nasm syntax because most assembly language programmers "
+"coming to FreeBSD from other operating systems will find it easier to "
+"understand. And, because, quite frankly, that is what I am used to."
+msgstr ""
+
+#. type: Title ===
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:92
+#, no-wrap
+msgid "The Linker"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:95
+msgid ""
+"The output of the assembler, like that of any compiler, needs to be linked "
+"to form an executable file."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:98
+msgid ""
+"The standard man:ld[1] linker comes with FreeBSD. It works with the code "
+"assembled with either assembler."
+msgstr ""
+
+#. type: Title ==
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:100
+#, no-wrap
+msgid "System Calls"
+msgstr ""
+
+#. type: Title ===
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:103
+#, no-wrap
+msgid "Default Calling Convention"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:107
+msgid ""
+"By default, the FreeBSD kernel uses the C calling convention. Further, "
+"although the kernel is accessed using `int 80h`, it is assumed the program "
+"will call a function that issues `int 80h`, rather than issuing `int 80h` "
+"directly."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:110
+msgid ""
+"This convention is very convenient, and quite superior to the Microsoft(R) "
+"convention used by MS-DOS(R). Why? Because the UNIX(R) convention allows "
+"any program written in any language to access the kernel."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:113
+msgid ""
+"An assembly language program can do that as well. For example, we could "
+"open a file:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:119
+#, no-wrap
+msgid ""
+"kernel:\n"
+"\tint\t80h\t; Call kernel\n"
+"\tret\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:128
+#, no-wrap
+msgid ""
+"open:\n"
+"\tpush\tdword mode\n"
+"\tpush\tdword flags\n"
+"\tpush\tdword path\n"
+"\tmov\teax, 5\n"
+"\tcall\tkernel\n"
+"\tadd\tesp, byte 12\n"
+"\tret\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:132
+msgid ""
+"This is a very clean and portable way of coding. If you need to port the "
+"code to a UNIX(R) system which uses a different interrupt, or a different "
+"way of passing parameters, all you need to change is the kernel procedure."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:136
+msgid ""
+"But assembly language programmers like to shave off cycles. The above "
+"example requires a `call/ret` combination. We can eliminate it by "
+"``push``ing an extra dword:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:147
+#, no-wrap
+msgid ""
+"open:\n"
+"\tpush\tdword mode\n"
+"\tpush\tdword flags\n"
+"\tpush\tdword path\n"
+"\tmov\teax, 5\n"
+"\tpush\teax\t\t; Or any other dword\n"
+"\tint\t80h\n"
+"\tadd\tesp, byte 16\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:150
+msgid ""
+"The `5` that we have placed in `EAX` identifies the kernel function, in this "
+"case `open`."
+msgstr ""
+
+#. type: Title ===
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:152
+#, no-wrap
+msgid "Alternate Calling Convention"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:157
+msgid ""
+"FreeBSD is an extremely flexible system. It offers other ways of calling "
+"the kernel. For it to work, however, the system must have Linux emulation "
+"installed."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:162
+msgid ""
+"Linux is a UNIX(R) like system. However, its kernel uses the same system-"
+"call convention of passing parameters in registers MS-DOS(R) does. As with "
+"the UNIX(R) convention, the function number is placed in `EAX`. The "
+"parameters, however, are not passed on the stack but in `EBX, ECX, EDX, ESI, "
+"EDI, EBP`:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:171
+#, no-wrap
+msgid ""
+"open:\n"
+"\tmov\teax, 5\n"
+"\tmov\tebx, path\n"
+"\tmov\tecx, flags\n"
+"\tmov\tedx, mode\n"
+"\tint\t80h\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:177
+msgid ""
+"This convention has a great disadvantage over the UNIX(R) way, at least as "
+"far as assembly language programming is concerned: Every time you make a "
+"kernel call you must `push` the registers, then `pop` them later. This "
+"makes your code bulkier and slower. Nevertheless, FreeBSD gives you a "
+"choice."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:180
+msgid ""
+"If you do choose the Linux convention, you must let the system know about "
+"it. After your program is assembled and linked, you need to brand the "
+"executable:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:184
+#, no-wrap
+msgid "% brandelf -t Linux filename\n"
+msgstr ""
+
+#. type: Title ===
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:187
+#, no-wrap
+msgid "Which Convention Should You Use?"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:192
+msgid ""
+"If you are coding specifically for FreeBSD, you should always use the "
+"UNIX(R) convention: It is faster, you can store global variables in "
+"registers, you do not have to brand the executable, and you do not impose "
+"the installation of the Linux emulation package on the target system."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:195
+msgid ""
+"If you want to create portable code that can also run on Linux, you will "
+"probably still want to give the FreeBSD users as efficient a code as "
+"possible. I will show you how you can accomplish that after I have "
+"explained the basics."
+msgstr ""
+
+#. type: Title ===
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:197
+#, no-wrap
+msgid "Call Numbers"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:201
+msgid ""
+"To tell the kernel which system service you are calling, place its number in "
+"`EAX`. Of course, you need to know what the number is."
+msgstr ""
+
+#. type: Title ====
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:203
+#, no-wrap
+msgid "The [.filename]#syscalls# File"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:207
+msgid ""
+"The numbers are listed in [.filename]#syscalls#. `locate syscalls` finds "
+"this file in several different formats, all produced automatically from [."
+"filename]#syscalls.master#."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:210
+msgid ""
+"You can find the master file for the default UNIX(R) calling convention in [."
+"filename]#/usr/src/sys/kern/syscalls.master#. If you need to use the other "
+"convention implemented in the Linux emulation mode, read [.filename]#/usr/"
+"src/sys/i386/linux/syscalls.master#."
+msgstr ""
+
+#. type: delimited block = 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:214
+msgid ""
+"Not only do FreeBSD and Linux use different calling conventions, they "
+"sometimes use different numbers for the same functions."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:217
+msgid "[.filename]#syscalls.master# describes how the call is to be made:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:228
+#, no-wrap
+msgid ""
+"0\tSTD\tNOHIDE\t{ int nosys(void); } syscall nosys_args int\n"
+"1\tSTD\tNOHIDE\t{ void exit(int rval); } exit rexit_args void\n"
+"2\tSTD\tPOSIX\t{ int fork(void); }\n"
+"3\tSTD\tPOSIX\t{ ssize_t read(int fd, void *buf, size_t nbyte); }\n"
+"4\tSTD\tPOSIX\t{ ssize_t write(int fd, const void *buf, size_t nbyte); }\n"
+"5\tSTD\tPOSIX\t{ int open(char *path, int flags, int mode); }\n"
+"6\tSTD\tPOSIX\t{ int close(int fd); }\n"
+"etc...\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:231
+msgid "It is the leftmost column that tells us the number to place in `EAX`."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:234
+msgid ""
+"The rightmost column tells us what parameters to `push`. They are "
+"``push``ed _from right to left_."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:236
+msgid ""
+"For example, to `open` a file, we need to `push` the `mode` first, then "
+"`flags`, then the address at which the `path` is stored."
+msgstr ""
+
+#. type: Title ==
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:238
+#, no-wrap
+msgid "Return Values"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:242
+msgid ""
+"A system call would not be useful most of the time if it did not return some "
+"kind of a value: The file descriptor of an open file, the number of bytes "
+"read to a buffer, the system time, etc."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:245
+msgid ""
+"Additionally, the system needs to inform us if an error occurs: A file does "
+"not exist, system resources are exhausted, we passed an invalid parameter, "
+"etc."
+msgstr ""
+
+#. type: Title ===
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:247
+#, no-wrap
+msgid "Man Pages"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:251
+msgid ""
+"The traditional place to look for information about various system calls "
+"under UNIX(R) systems are the manual pages. FreeBSD describes its system "
+"calls in section 2, sometimes in section 3."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:253
+msgid "For example, man:open[2] says:"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:257
+msgid ""
+"If successful, `open()` returns a non-negative integer, termed a file "
+"descriptor. It returns `-1` on failure, and sets `errno` to indicate the "
+"error."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:259
+msgid ""
+"The assembly language programmer new to UNIX(R) and FreeBSD will immediately "
+"ask the puzzling question: Where is `errno` and how do I get to it?"
+msgstr ""
+
+#. type: delimited block = 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:264
+msgid ""
+"The information presented in the manual pages applies to C programs. The "
+"assembly language programmer needs additional information."
+msgstr ""
+
+#. type: Title ===
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:267
+#, no-wrap
+msgid "Where Are the Return Values?"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:272
+msgid ""
+"Unfortunately, it depends... For most system calls it is in `EAX`, but not "
+"for all. A good rule of thumb, when working with a system call for the "
+"first time, is to look for the return value in `EAX`. If it is not there, "
+"you need further research."
+msgstr ""
+
+#. type: delimited block = 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:278
+msgid ""
+"I am aware of one system call that returns the value in `EDX`: `SYS_fork`. "
+"All others I have worked with use `EAX`. But I have not worked with them "
+"all yet."
+msgstr ""
+
+#. type: delimited block = 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:283
+msgid ""
+"If you cannot find the answer here or anywhere else, study libc source code "
+"and see how it interfaces with the kernel."
+msgstr ""
+
+#. type: Title ===
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:286
+#, no-wrap
+msgid "Where Is `errno`?"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:289
+msgid "Actually, nowhere..."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:292
+msgid ""
+"`errno` is part of the C language, not the UNIX(R) kernel. When accessing "
+"kernel services directly, the error code is returned in `EAX`, the same "
+"register the proper return value generally ends up in."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:296
+msgid ""
+"This makes perfect sense. If there is no error, there is no error code. If "
+"there is an error, there is no return value. One register can contain "
+"either."
+msgstr ""
+
+#. type: Title ===
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:298
+#, no-wrap
+msgid "Determining an Error Occurred"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:301
+msgid ""
+"When using the standard FreeBSD calling convention, the `carry flag` is "
+"cleared upon success, set upon failure."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:304
+msgid ""
+"When using the Linux emulation mode, the signed value in `EAX` is non-"
+"negative upon success, and contains the return value. In case of an error, "
+"the value is negative, i.e., `-errno`."
+msgstr ""
+
+#. type: Title ==
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:306
+#, no-wrap
+msgid "Creating Portable Code"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:311
+msgid ""
+"Portability is generally not one of the strengths of assembly language. "
+"Yet, writing assembly language programs for different platforms is possible, "
+"especially with nasm. I have written assembly language libraries that can "
+"be assembled for such different operating systems as Windows(R) and FreeBSD."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:313
+msgid ""
+"It is all the more possible when you want your code to run on two platforms "
+"which, while different, are based on similar architectures."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:317
+msgid ""
+"For example, FreeBSD is UNIX(R), Linux is UNIX(R) like. I only mentioned "
+"three differences between them (from an assembly language programmer's "
+"perspective): The calling convention, the function numbers, and the way of "
+"returning values."
+msgstr ""
+
+#. type: Title ===
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:319
+#, no-wrap
+msgid "Dealing with Function Numbers"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:324
+msgid ""
+"In many cases the function numbers are the same. However, even when they "
+"are not, the problem is easy to deal with: Instead of using numbers in your "
+"code, use constants which you have declared differently depending on the "
+"target architecture:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:332
+#, no-wrap
+msgid ""
+"%ifdef\tLINUX\n"
+"%define\tSYS_execve\t11\n"
+"%else\n"
+"%define\tSYS_execve\t59\n"
+"%endif\n"
+msgstr ""
+
+#. type: Title ===
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:335
+#, no-wrap
+msgid "Dealing with Conventions"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:338
+msgid ""
+"Both, the calling convention, and the return value (the `errno` problem) can "
+"be resolved with macros:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:342
+#, no-wrap
+msgid "%ifdef\tLINUX\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:346
+#, no-wrap
+msgid ""
+"%macro\tsystem\t0\n"
+"\tcall\tkernel\n"
+"%endmacro\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:355
+#, no-wrap
+msgid ""
+"align 4\n"
+"kernel:\n"
+"\tpush\tebx\n"
+"\tpush\tecx\n"
+"\tpush\tedx\n"
+"\tpush\tesi\n"
+"\tpush\tedi\n"
+"\tpush\tebp\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:362
+#, no-wrap
+msgid ""
+"\tmov\tebx, [esp+32]\n"
+"\tmov\tecx, [esp+36]\n"
+"\tmov\tedx, [esp+40]\n"
+"\tmov\tesi, [esp+44]\n"
+"\tmov\tebp, [esp+48]\n"
+"\tint\t80h\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:369
+#, no-wrap
+msgid ""
+"\tpop\tebp\n"
+"\tpop\tedi\n"
+"\tpop\tesi\n"
+"\tpop\tedx\n"
+"\tpop\tecx\n"
+"\tpop\tebx\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:374
+#, no-wrap
+msgid ""
+"\tor\teax, eax\n"
+"\tjs\t.errno\n"
+"\tclc\n"
+"\tret\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:379
+#, no-wrap
+msgid ""
+".errno:\n"
+"\tneg\teax\n"
+"\tstc\n"
+"\tret\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:381
+#, no-wrap
+msgid "%else\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:385
+#, no-wrap
+msgid ""
+"%macro\tsystem\t0\n"
+"\tint\t80h\n"
+"%endmacro\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:387
+#, no-wrap
+msgid "%endif\n"
+msgstr ""
+
+#. type: Title ===
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:390
+#, no-wrap
+msgid "Dealing with Other Portability Issues"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:394
+msgid ""
+"The above solutions can handle most cases of writing code portable between "
+"FreeBSD and Linux. Nevertheless, with some kernel services the differences "
+"are deeper."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:397
+msgid ""
+"In that case, you need to write two different handlers for those particular "
+"system calls, and use conditional assembly. Luckily, most of your code does "
+"something other than calling the kernel, so usually you will only need a few "
+"such conditional sections in your code."
+msgstr ""
+
+#. type: Title ===
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:399
+#, no-wrap
+msgid "Using a Library"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:403
+msgid ""
+"You can avoid portability issues in your main code altogether by writing a "
+"library of system calls. Create a separate library for FreeBSD, a different "
+"one for Linux, and yet other libraries for more operating systems."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:408
+msgid ""
+"In your library, write a separate function (or procedure, if you prefer the "
+"traditional assembly language terminology) for each system call. Use the C "
+"calling convention of passing parameters. But still use `EAX` to pass the "
+"call number in. In that case, your FreeBSD library can be very simple, as "
+"many seemingly different functions can be just labels to the same code:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:416
+#, no-wrap
+msgid ""
+"sys.open:\n"
+"sys.close:\n"
+"[etc...]\n"
+"\tint\t80h\n"
+"\tret\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:420
+msgid ""
+"Your Linux library will require more different functions. But even here you "
+"can group system calls using the same number of parameters:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:431
+#, no-wrap
+msgid ""
+"sys.exit:\n"
+"sys.close:\n"
+"[etc... one-parameter functions]\n"
+"\tpush\tebx\n"
+"\tmov\tebx, [esp+12]\n"
+"\tint\t80h\n"
+"\tpop\tebx\n"
+"\tjmp\tsys.return\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:433
+#, no-wrap
+msgid "...\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:439
+#, no-wrap
+msgid ""
+"sys.return:\n"
+"\tor\teax, eax\n"
+"\tjs\tsys.err\n"
+"\tclc\n"
+"\tret\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:444
+#, no-wrap
+msgid ""
+"sys.err:\n"
+"\tneg\teax\n"
+"\tstc\n"
+"\tret\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:451
+msgid ""
+"The library approach may seem inconvenient at first because it requires you "
+"to produce a separate file your code depends on. But it has many "
+"advantages: For one, you only need to write it once and can use it for all "
+"your programs. You can even let other assembly language programmers use it, "
+"or perhaps use one written by someone else. But perhaps the greatest "
+"advantage of the library is that your code can be ported to other systems, "
+"even by other programmers, by simply writing a new library without any "
+"changes to your code."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:453
+msgid ""
+"If you do not like the idea of having a library, you can at least place all "
+"your system calls in a separate assembly language file and link it with your "
+"main program. Here, again, all porters have to do is create a new object "
+"file to link with your main program."
+msgstr ""
+
+#. type: Title ===
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:455
+#, no-wrap
+msgid "Using an Include File"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:458
+msgid ""
+"If you are releasing your software as (or with) source code, you can use "
+"macros and place them in a separate file, which you include in your code."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:461
+msgid ""
+"Porters of your software will simply write a new include file. No library "
+"or external object file is necessary, yet your code is portable without any "
+"need to edit the code."
+msgstr ""
+
+#. type: delimited block = 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:466
+msgid ""
+"This is the approach we will use throughout this chapter. We will name our "
+"include file [.filename]#system.inc#, and add to it whenever we deal with a "
+"new system call."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:469
+msgid ""
+"We can start our [.filename]#system.inc# by declaring the standard file "
+"descriptors:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:475
+#, no-wrap
+msgid ""
+"%define\tstdin\t0\n"
+"%define\tstdout\t1\n"
+"%define\tstderr\t2\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:478
+msgid "Next, we create a symbolic name for each system call:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:487
+#, no-wrap
+msgid ""
+"%define\tSYS_nosys\t0\n"
+"%define\tSYS_exit\t1\n"
+"%define\tSYS_fork\t2\n"
+"%define\tSYS_read\t3\n"
+"%define\tSYS_write\t4\n"
+"; [etc...]\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:490
+msgid ""
+"We add a short, non-global procedure with a long name, so we do not "
+"accidentally reuse the name in our code:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:498
+#, no-wrap
+msgid ""
+"section\t.text\n"
+"align 4\n"
+"access.the.bsd.kernel:\n"
+"\tint\t80h\n"
+"\tret\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:501
+msgid "We create a macro which takes one argument, the syscall number:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:508
+#, no-wrap
+msgid ""
+"%macro\tsystem\t1\n"
+"\tmov\teax, %1\n"
+"\tcall\taccess.the.bsd.kernel\n"
+"%endmacro\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:512
+msgid ""
+"Finally, we create macros for each syscall. These macros take no arguments."
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:518
+#, no-wrap
+msgid ""
+"%macro\tsys.exit\t0\n"
+"\tsystem\tSYS_exit\n"
+"%endmacro\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:522
+#, no-wrap
+msgid ""
+"%macro\tsys.fork\t0\n"
+"\tsystem\tSYS_fork\n"
+"%endmacro\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:526
+#, no-wrap
+msgid ""
+"%macro\tsys.read\t0\n"
+"\tsystem\tSYS_read\n"
+"%endmacro\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:530
+#, no-wrap
+msgid ""
+"%macro\tsys.write\t0\n"
+"\tsystem\tSYS_write\n"
+"%endmacro\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:532
+#, no-wrap
+msgid "; [etc...]\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:536
+msgid ""
+"Go ahead, enter it into your editor and save it as [.filename]#system.inc#. "
+"We will add more to it as we discuss more syscalls."
+msgstr ""
+
+#. type: Title ==
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:538
+#, no-wrap
+msgid "Our First Program"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:541
+msgid "We are now ready for our first program, the mandatory Hello, World!"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:560
+#, no-wrap
+msgid ""
+"1:\t%include\t'system.inc'\n"
+" 2:\n"
+" 3:\tsection\t.data\n"
+" 4:\thello\tdb\t'Hello, World!', 0Ah\n"
+" 5:\thbytes\tequ\t$-hello\n"
+" 6:\n"
+" 7:\tsection\t.text\n"
+" 8:\tglobal\t_start\n"
+" 9:\t_start:\n"
+"10:\tpush\tdword hbytes\n"
+"11:\tpush\tdword hello\n"
+"12:\tpush\tdword stdout\n"
+"13:\tsys.write\n"
+"14:\n"
+"15:\tpush\tdword 0\n"
+"16:\tsys.exit\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:563
+msgid ""
+"Here is what it does: Line 1 includes the defines, the macros, and the code "
+"from [.filename]#system.inc#."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:567
+msgid ""
+"Lines 3-5 are the data: Line 3 starts the data section/segment. Line 4 "
+"contains the string \"Hello, World!\" followed by a new line (`0Ah`). Line "
+"5 creates a constant that contains the length of the string from line 4 in "
+"bytes."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:571
+msgid ""
+"Lines 7-16 contain the code. Note that FreeBSD uses the _elf_ file format "
+"for its executables, which requires every program to start at the point "
+"labeled `_start` (or, more precisely, the linker expects that). This label "
+"has to be global."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:573
+msgid ""
+"Lines 10-13 ask the system to write `hbytes` bytes of the `hello` string to "
+"`stdout`."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:576
+msgid ""
+"Lines 15-16 ask the system to end the program with the return value of `0`. "
+"The `SYS_exit` syscall never returns, so the code ends there."
+msgstr ""
+
+#. type: delimited block = 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:584
+msgid ""
+"If you have come to UNIX(R) from MS-DOS(R) assembly language background, you "
+"may be used to writing directly to the video hardware. You will never have "
+"to worry about this in FreeBSD, or any other flavor of UNIX(R). As far as "
+"you are concerned, you are writing to a file known as [.filename]#stdout#. "
+"This can be the video screen, or a telnet terminal, or an actual file, or "
+"even the input of another program. Which one it is, is for the system to "
+"figure out."
+msgstr ""
+
+#. type: Title ===
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:587
+#, no-wrap
+msgid "Assembling the Code"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:591
+msgid ""
+"Type the code (except the line numbers) in an editor, and save it in a file "
+"named [.filename]#hello.asm#. You need nasm to assemble it."
+msgstr ""
+
+#. type: Title ====
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:593
+#, no-wrap
+msgid "Installing nasm"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:596
+msgid "If you do not have nasm, type:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:605
+#, no-wrap
+msgid ""
+"% su\n"
+"Password:your root password\n"
+"# cd /usr/ports/devel/nasm\n"
+"# make install\n"
+"# exit\n"
+"%\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:608
+msgid ""
+"You may type `make install clean` instead of just `make install` if you do "
+"not want to keep nasm source code."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:610
+msgid ""
+"Either way, FreeBSD will automatically download nasm from the Internet, "
+"compile it, and install it on your system."
+msgstr ""
+
+#. type: delimited block = 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:615
+msgid ""
+"If your system is not FreeBSD, you need to get nasm from its https://"
+"sourceforge.net/projects/nasm[home page]. You can still use it to assemble "
+"FreeBSD code."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:618
+msgid "Now you can assemble, link, and run the code:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:626
+#, no-wrap
+msgid ""
+"% nasm -f elf hello.asm\n"
+"% ld -s -o hello hello.o\n"
+"% ./hello\n"
+"Hello, World!\n"
+"%\n"
+msgstr ""
+
+#. type: Title ==
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:629
+#, no-wrap
+msgid "Writing UNIX(R) Filters"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:632
+msgid ""
+"A common type of UNIX(R) application is a filter-a program that reads data "
+"from the [.filename]#stdin#, processes it somehow, then writes the result to "
+"[.filename]#stdout#."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:635
+msgid ""
+"In this chapter, we shall develop a simple filter, and learn how to read "
+"from [.filename]#stdin# and write to [.filename]#stdout#. This filter will "
+"convert each byte of its input into a hexadecimal number followed by a blank "
+"space."
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:639
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:733
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:823
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:951
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1218
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2336
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3334
+#, no-wrap
+msgid "%include\t'system.inc'\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:643
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:737
+#, no-wrap
+msgid ""
+"section\t.data\n"
+"hex\tdb\t'0123456789ABCDEF'\n"
+"buffer\tdb\t0, 0, ' '\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:655
+#, no-wrap
+msgid ""
+"section\t.text\n"
+"global\t_start\n"
+"_start:\n"
+"\t; read a byte from stdin\n"
+"\tpush\tdword 1\n"
+"\tpush\tdword buffer\n"
+"\tpush\tdword stdin\n"
+"\tsys.read\n"
+"\tadd\tesp, byte 12\n"
+"\tor\teax, eax\n"
+"\tje\t.done\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:665
+#, no-wrap
+msgid ""
+"\t; convert it to hex\n"
+"\tmovzx\teax, byte [buffer]\n"
+"\tmov\tedx, eax\n"
+"\tshr\tdl, 4\n"
+"\tmov\tdl, [hex+edx]\n"
+"\tmov\t[buffer], dl\n"
+"\tand\tal, 0Fh\n"
+"\tmov\tal, [hex+eax]\n"
+"\tmov\t[buffer+1], al\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:673
+#, no-wrap
+msgid ""
+"\t; print it\n"
+"\tpush\tdword 3\n"
+"\tpush\tdword buffer\n"
+"\tpush\tdword stdout\n"
+"\tsys.write\n"
+"\tadd\tesp, byte 12\n"
+"\tjmp\tshort _start\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:677
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:780
+#, no-wrap
+msgid ""
+".done:\n"
+"\tpush\tdword 0\n"
+"\tsys.exit\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:685
+msgid ""
+"In the data section we create an array called `hex`. It contains the 16 "
+"hexadecimal digits in ascending order. The array is followed by a buffer "
+"which we will use for both input and output. The first two bytes of the "
+"buffer are initially set to `0`. This is where we will write the two "
+"hexadecimal digits (the first byte also is where we will read the input). "
+"The third byte is a space."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:687
+msgid ""
+"The code section consists of four parts: Reading the byte, converting it to "
+"a hexadecimal number, writing the result, and eventually exiting the program."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:693
+msgid ""
+"To read the byte, we ask the system to read one byte from [."
+"filename]#stdin#, and store it in the first byte of the `buffer`. The "
+"system returns the number of bytes read in `EAX`. This will be `1` while "
+"data is coming, or `0`, when no more input data is available. Therefore, we "
+"check the value of `EAX`. If it is `0`, we jump to `.done`, otherwise we "
+"continue."
+msgstr ""
+
+#. type: delimited block = 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:697
+msgid ""
+"For simplicity sake, we are ignoring the possibility of an error condition "
+"at this time."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:702
+msgid ""
+"The hexadecimal conversion reads the byte from the `buffer` into `EAX`, or "
+"actually just `AL`, while clearing the remaining bits of `EAX` to zeros. We "
+"also copy the byte to `EDX` because we need to convert the upper four bits "
+"(nibble) separately from the lower four bits. We store the result in the "
+"first two bytes of the buffer."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:705
+msgid ""
+"Next, we ask the system to write the three bytes of the buffer, i.e., the "
+"two hexadecimal digits and the blank space, to [.filename]#stdout#. We then "
+"jump back to the beginning of the program and process the next byte."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:707
+msgid ""
+"Once there is no more input left, we ask the system to exit our program, "
+"returning a zero, which is the traditional value meaning the program was "
+"successful."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:709
+msgid ""
+"Go ahead, and save the code in a file named [.filename]#hex.asm#, then type "
+"the following (the `^D` means press the control key and type `D` while "
+"holding the control key down):"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:718
+#, no-wrap
+msgid ""
+"% nasm -f elf hex.asm\n"
+"% ld -s -o hex hex.o\n"
+"% ./hex\n"
+"Hello, World!\n"
+"48 65 6C 6C 6F 2C 20 57 6F 72 6C 64 21 0A Here I come!\n"
+"48 65 72 65 20 49 20 63 6F 6D 65 21 0A ^D %\n"
+msgstr ""
+
+#. type: delimited block = 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:724
+msgid ""
+"If you are migrating to UNIX(R) from MS-DOS(R), you may be wondering why "
+"each line ends with `0A` instead of `0D 0A`. This is because UNIX(R) does "
+"not use the cr/lf convention, but a \"new line\" convention, which is `0A` "
+"in hexadecimal."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:729
+msgid ""
+"Can we improve this? Well, for one, it is a bit confusing because once we "
+"have converted a line of text, our input no longer starts at the beginning "
+"of the line. We can modify it to print a new line instead of a space after "
+"each `0A`:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:742
+#, no-wrap
+msgid ""
+"section\t.text\n"
+"global\t_start\n"
+"_start:\n"
+"\tmov\tcl, ' '\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:752
+#, no-wrap
+msgid ""
+".loop:\n"
+"\t; read a byte from stdin\n"
+"\tpush\tdword 1\n"
+"\tpush\tdword buffer\n"
+"\tpush\tdword stdin\n"
+"\tsys.read\n"
+"\tadd\tesp, byte 12\n"
+"\tor\teax, eax\n"
+"\tje\t.done\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:759
+#, no-wrap
+msgid ""
+"\t; convert it to hex\n"
+"\tmovzx\teax, byte [buffer]\n"
+"\tmov\t[buffer+2], cl\n"
+"\tcmp\tal, 0Ah\n"
+"\tjne\t.hex\n"
+"\tmov\t[buffer+2], al\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:768
+#, no-wrap
+msgid ""
+".hex:\n"
+"\tmov\tedx, eax\n"
+"\tshr\tdl, 4\n"
+"\tmov\tdl, [hex+edx]\n"
+"\tmov\t[buffer], dl\n"
+"\tand\tal, 0Fh\n"
+"\tmov\tal, [hex+eax]\n"
+"\tmov\t[buffer+1], al\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:776
+#, no-wrap
+msgid ""
+"\t; print it\n"
+"\tpush\tdword 3\n"
+"\tpush\tdword buffer\n"
+"\tpush\tdword stdout\n"
+"\tsys.write\n"
+"\tadd\tesp, byte 12\n"
+"\tjmp\tshort .loop\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:784
+msgid ""
+"We have stored the space in the `CL` register. We can do this safely "
+"because, unlike Microsoft(R) Windows(R), UNIX(R) system calls do not modify "
+"the value of any register they do not use to return a value in."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:788
+msgid ""
+"That means we only need to set `CL` once. We have, therefore, added a new "
+"label `.loop` and jump to it for the next byte instead of jumping at "
+"`_start`. We have also added the `.hex` label so we can either have a blank "
+"space or a new line as the third byte of the `buffer`."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:790
+msgid ""
+"Once you have changed [.filename]#hex.asm# to reflect these changes, type:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:801
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1060
+#, no-wrap
+msgid ""
+"% nasm -f elf hex.asm\n"
+"% ld -s -o hex hex.o\n"
+"% ./hex\n"
+"Hello, World!\n"
+"48 65 6C 6C 6F 2C 20 57 6F 72 6C 64 21 0A\n"
+"Here I come!\n"
+"48 65 72 65 20 49 20 63 6F 6D 65 21 0A\n"
+"^D %\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:805
+msgid ""
+"That looks better. But this code is quite inefficient! We are making a "
+"system call for every single byte twice (once to read it, another time to "
+"write the output)."
+msgstr ""
+
+#. type: Title ==
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:807
+#, no-wrap
+msgid "Buffered Input and Output"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:812
+msgid ""
+"We can improve the efficiency of our code by buffering our input and "
+"output. We create an input buffer and read a whole sequence of bytes at one "
+"time. Then we fetch them one by one from the buffer."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:815
+msgid ""
+"We also create an output buffer. We store our output in it until it is "
+"full. At that time we ask the kernel to write the contents of the buffer to "
+"[.filename]#stdout#."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:819
+msgid ""
+"The program ends when there is no more input. But we still need to ask the "
+"kernel to write the contents of our output buffer to [.filename]#stdout# one "
+"last time, otherwise some of our output would make it to the output buffer, "
+"but never be sent out. Do not forget that, or you will be wondering why "
+"some of your output is missing."
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:825
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:953
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1220
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2338
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3336
+#, no-wrap
+msgid "%define\tBUFSIZE\t2048\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:828
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:956
+#, no-wrap
+msgid ""
+"section\t.data\n"
+"hex\tdb\t'0123456789ABCDEF'\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:832
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:960
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1229
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2352
+#, no-wrap
+msgid ""
+"section .bss\n"
+"ibuffer\tresb\tBUFSIZE\n"
+"obuffer\tresb\tBUFSIZE\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:840
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:968
+#, no-wrap
+msgid ""
+"section\t.text\n"
+"global\t_start\n"
+"_start:\n"
+"\tsub\teax, eax\n"
+"\tsub\tebx, ebx\n"
+"\tsub\tecx, ecx\n"
+"\tmov\tedi, obuffer\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:844
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:972
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2500
+#, no-wrap
+msgid ""
+".loop:\n"
+"\t; read a byte from stdin\n"
+"\tcall\tgetchar\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:850
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:978
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1282
+#, no-wrap
+msgid ""
+"\t; convert it to hex\n"
+"\tmov\tdl, al\n"
+"\tshr\tal, 4\n"
+"\tmov\tal, [hex+eax]\n"
+"\tcall\tputchar\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:855
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:983
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1287
+#, no-wrap
+msgid ""
+"\tmov\tal, dl\n"
+"\tand\tal, 0Fh\n"
+"\tmov\tal, [hex+eax]\n"
+"\tcall\tputchar\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:860
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:988
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1292
+#, no-wrap
+msgid ""
+"\tmov\tal, ' '\n"
+"\tcmp\tdl, 0Ah\n"
+"\tjne\t.put\n"
+"\tmov\tal, dl\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:864
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2511
+#, no-wrap
+msgid ""
+".put:\n"
+"\tcall\tputchar\n"
+"\tjmp\tshort .loop\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:869
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1000
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1304
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2533
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3847
+#, no-wrap
+msgid ""
+"align 4\n"
+"getchar:\n"
+"\tor\tebx, ebx\n"
+"\tjne\t.fetch\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:871
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1002
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1306
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2535
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3849
+#, no-wrap
+msgid "\tcall\tread\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:876
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1007
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1311
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2540
+#, no-wrap
+msgid ""
+".fetch:\n"
+"\tlodsb\n"
+"\tdec\tebx\n"
+"\tret\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:889
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1020
+#, no-wrap
+msgid ""
+"read:\n"
+"\tpush\tdword BUFSIZE\n"
+"\tmov\tesi, ibuffer\n"
+"\tpush\tesi\n"
+"\tpush\tdword stdin\n"
+"\tsys.read\n"
+"\tadd\tesp, byte 12\n"
+"\tmov\tebx, eax\n"
+"\tor\teax, eax\n"
+"\tje\t.done\n"
+"\tsub\teax, eax\n"
+"\tret\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:895
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1026
+#, no-wrap
+msgid ""
+"align 4\n"
+".done:\n"
+"\tcall\twrite\t\t; flush output buffer\n"
+"\tpush\tdword 0\n"
+"\tsys.exit\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:903
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1034
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1347
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2580
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3886
+#, no-wrap
+msgid ""
+"align 4\n"
+"putchar:\n"
+"\tstosb\n"
+"\tinc\tecx\n"
+"\tcmp\tecx, BUFSIZE\n"
+"\tje\twrite\n"
+"\tret\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:915
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1046
+#, no-wrap
+msgid ""
+"align 4\n"
+"write:\n"
+"\tsub\tedi, ecx\t; start of buffer\n"
+"\tpush\tecx\n"
+"\tpush\tedi\n"
+"\tpush\tdword stdout\n"
+"\tsys.write\n"
+"\tadd\tesp, byte 12\n"
+"\tsub\teax, eax\n"
+"\tsub\tecx, ecx\t; buffer is empty now\n"
+"\tret\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:921
+msgid ""
+"We now have a third section in the source code, named `.bss`. This section "
+"is not included in our executable file, and, therefore, cannot be "
+"initialized. We use `resb` instead of `db`. It simply reserves the "
+"requested size of uninitialized memory for our use."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:925
+msgid ""
+"We take advantage of the fact that the system does not modify the registers: "
+"We use registers for what, otherwise, would have to be global variables "
+"stored in the `.data` section. This is also why the UNIX(R) convention of "
+"passing parameters to system calls on the stack is superior to the Microsoft "
+"convention of passing them in the registers: We can keep the registers for "
+"our own use."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:929
+msgid ""
+"We use `EDI` and `ESI` as pointers to the next byte to be read from or "
+"written to. We use `EBX` and `ECX` to keep count of the number of bytes in "
+"the two buffers, so we know when to dump the output to, or read more input "
+"from, the system."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:931
+msgid "Let us see how it works now:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:942
+#, no-wrap
+msgid ""
+"% nasm -f elf hex.asm\n"
+"% ld -s -o hex hex.o\n"
+"% ./hex\n"
+"Hello, World!\n"
+"Here I come!\n"
+"48 65 6C 6C 6F 2C 20 57 6F 72 6C 64 21 0A\n"
+"48 65 72 65 20 49 20 63 6F 6D 65 21 0A\n"
+"^D %\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:947
+msgid ""
+"Not what you expected? The program did not print the output until we pressed "
+"`^D`. That is easy to fix by inserting three lines of code to write the "
+"output every time we have converted a new line to `0A`. I have marked the "
+"three lines with > (do not copy the > in your [.filename]#hex.asm#)."
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:995
+#, no-wrap
+msgid ""
+".put:\n"
+"\tcall\tputchar\n"
+">\tcmp\tal, 0Ah\n"
+">\tjne\t.loop\n"
+">\tcall\twrite\n"
+"\tjmp\tshort .loop\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1049
+msgid "Now, let us see how it works:"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1063
+msgid "Not bad for a 644-byte executable, is it!"
+msgstr ""
+
+#. type: delimited block = 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1068
+msgid ""
+"This approach to buffered input/output still contains a hidden danger. I "
+"will discuss-and fix-it later, when I talk about the <<x86-buffered-dark-"
+"side,dark side of buffering>>."
+msgstr ""
+
+#. type: Title ===
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1071
+#, no-wrap
+msgid "How to Unread a Character"
+msgstr ""
+
+#. type: delimited block = 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1077
+msgid ""
+"This may be a somewhat advanced topic, mostly of interest to programmers "
+"familiar with the theory of compilers. If you wish, you may <<x86-command-"
+"line,skip to the next section>>, and perhaps read this later."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1083
+msgid ""
+"While our sample program does not require it, more sophisticated filters "
+"often need to look ahead. In other words, they may need to see what the "
+"next character is (or even several characters). If the next character is of "
+"a certain value, it is part of the token currently being processed. "
+"Otherwise, it is not."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1087
+msgid ""
+"For example, you may be parsing the input stream for a textual string (e.g., "
+"when implementing a language compiler): If a character is followed by "
+"another character, or perhaps a digit, it is part of the token you are "
+"processing. If it is followed by white space, or some other value, then it "
+"is not part of the current token."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1089
+msgid ""
+"This presents an interesting problem: How to return the next character back "
+"to the input stream, so it can be read again later?"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1093
+msgid ""
+"One possible solution is to store it in a character variable, then set a "
+"flag. We can modify `getchar` to check the flag, and if it is set, fetch "
+"the byte from that variable instead of the input buffer, and reset the "
+"flag. But, of course, that slows us down."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1098
+msgid ""
+"The C language has an `ungetc()` function, just for that purpose. Is there "
+"a quick way to implement it in our code? I would like you to scroll back up "
+"and take a look at the `getchar` procedure and see if you can find a nice "
+"and fast solution before reading the next paragraph. Then come back here "
+"and see my own solution."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1100
+msgid ""
+"The key to returning a character back to the stream is in how we are getting "
+"the characters to start with:"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1103
+msgid ""
+"First we check if the buffer is empty by testing the value of `EBX`. If it "
+"is zero, we call the `read` procedure."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1106
+msgid ""
+"If we do have a character available, we use `lodsb`, then decrease the value "
+"of `EBX`. The `lodsb` instruction is effectively identical to:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1111
+#, no-wrap
+msgid ""
+"mov\tal, [esi]\n"
+"\tinc\tesi\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1116
+msgid ""
+"The byte we have fetched remains in the buffer until the next time `read` is "
+"called. We do not know when that happens, but we do know it will not happen "
+"until the next call to `getchar`. Hence, to \"return\" the last-read byte "
+"back to the stream, all we have to do is decrease the value of `ESI` and "
+"increase the value of `EBX`:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1123
+#, no-wrap
+msgid ""
+"ungetc:\n"
+"\tdec\tesi\n"
+"\tinc\tebx\n"
+"\tret\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1127
+msgid ""
+"But, be careful! We are perfectly safe doing this if our look-ahead is at "
+"most one character at a time. If we are examining more than one upcoming "
+"character and call `ungetc` several times in a row, it will work most of the "
+"time, but not all the time (and will be tough to debug). Why?"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1130
+msgid ""
+"Because as long as `getchar` does not have to call `read`, all of the pre-"
+"read bytes are still in the buffer, and our `ungetc` works without a "
+"glitch. But the moment `getchar` calls `read`, the contents of the buffer "
+"change."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1132
+msgid ""
+"We can always rely on `ungetc` working properly on the last character we "
+"have read with `getchar`, but not on anything we have read before that."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1134
+msgid ""
+"If your program reads more than one byte ahead, you have at least two "
+"choices:"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1137
+msgid ""
+"If possible, modify the program so it only reads one byte ahead. This is "
+"the simplest solution."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1141
+msgid ""
+"If that option is not available, first of all determine the maximum number "
+"of characters your program needs to return to the input stream at one time. "
+"Increase that number slightly, just to be sure, preferably to a multiple of "
+"16-so it aligns nicely. Then modify the `.bss` section of your code, and "
+"create a small \"spare\" buffer right before your input buffer, something "
+"like this:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1148
+#, no-wrap
+msgid ""
+"section\t.bss\n"
+"\tresb\t16\t; or whatever the value you came up with\n"
+"ibuffer\tresb\tBUFSIZE\n"
+"obuffer\tresb\tBUFSIZE\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1151
+msgid ""
+"You also need to modify your `ungetc` to pass the value of the byte to unget "
+"in `AL`:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1159
+#, no-wrap
+msgid ""
+"ungetc:\n"
+"\tdec\tesi\n"
+"\tinc\tebx\n"
+"\tmov\t[esi], al\n"
+"\tret\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1162
+msgid ""
+"With this modification, you can call `ungetc` up to 17 times in a row safely "
+"(the first call will still be within the buffer, the remaining 16 may be "
+"either within the buffer or within the \"spare\")."
+msgstr ""
+
+#. type: Title ==
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1164
+#, no-wrap
+msgid "Command Line Arguments"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1168
+msgid ""
+"Our hex program will be more useful if it can read the names of an input and "
+"output file from its command line, i.e., if it can process the command line "
+"arguments. But... Where are they?"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1172
+msgid ""
+"Before a UNIX(R) system starts a program, it ``push``es some data on the "
+"stack, then jumps at the `_start` label of the program. Yes, I said jumps, "
+"not calls. That means the data can be accessed by reading `[esp+offset]`, "
+"or by simply ``pop``ping it."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1175
+msgid ""
+"The value at the top of the stack contains the number of command line "
+"arguments. It is traditionally called `argc`, for \"argument count.\""
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1180
+msgid ""
+"Command line arguments follow next, all `argc` of them. These are typically "
+"referred to as `argv`, for \"argument value(s).\" That is, we get `argv[0]`, "
+"`argv[1]`, `...`, `argv[argc-1]`. These are not the actual arguments, but "
+"pointers to arguments, i.e., memory addresses of the actual arguments. The "
+"arguments themselves are NUL-terminated character strings."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1182
+msgid ""
+"The `argv` list is followed by a NULL pointer, which is simply a `0`. There "
+"is more, but this is enough for our purposes right now."
+msgstr ""
+
+#. type: delimited block = 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1187
+msgid ""
+"If you have come from the MS-DOS(R) programming environment, the main "
+"difference is that each argument is in a separate string. The second "
+"difference is that there is no practical limit on how many arguments there "
+"can be."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1191
+msgid ""
+"Armed with this knowledge, we are almost ready for the next version of [."
+"filename]#hex.asm#. First, however, we need to add a few lines to [."
+"filename]#system.inc#:"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1193
+msgid ""
+"First, we need to add two new entries to our list of system call numbers:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1198
+#, no-wrap
+msgid ""
+"%define\tSYS_open\t5\n"
+"%define\tSYS_close\t6\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1201
+msgid "Then we add two new macros at the end of the file:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1207
+#, no-wrap
+msgid ""
+"%macro\tsys.open\t0\n"
+"\tsystem\tSYS_open\n"
+"%endmacro\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1211
+#, no-wrap
+msgid ""
+"%macro\tsys.close\t0\n"
+"\tsystem\tSYS_close\n"
+"%endmacro\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1214
+msgid "Here, then, is our modified source code:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1225
+#, no-wrap
+msgid ""
+"section\t.data\n"
+"fd.in\tdd\tstdin\n"
+"fd.out\tdd\tstdout\n"
+"hex\tdb\t'0123456789ABCDEF'\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1235
+#, no-wrap
+msgid ""
+"section\t.text\n"
+"align 4\n"
+"err:\n"
+"\tpush\tdword 1\t\t; return failure\n"
+"\tsys.exit\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1240
+#, no-wrap
+msgid ""
+"align 4\n"
+"global\t_start\n"
+"_start:\n"
+"\tadd\tesp, byte 8\t; discard argc and argv[0]\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1243
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1255
+#, no-wrap
+msgid ""
+"\tpop\tecx\n"
+"\tjecxz\t.init\t\t; no more arguments\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1249
+#, no-wrap
+msgid ""
+"\t; ECX contains the path to input file\n"
+"\tpush\tdword 0\t\t; O_RDONLY\n"
+"\tpush\tecx\n"
+"\tsys.open\n"
+"\tjc\terr\t\t; open failed\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1252
+#, no-wrap
+msgid ""
+"\tadd\tesp, byte 8\n"
+"\tmov\t[fd.in], eax\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1263
+#, no-wrap
+msgid ""
+"\t; ECX contains the path to output file\n"
+"\tpush\tdword 420\t; file mode (644 octal)\n"
+"\tpush\tdword 0200h | 0400h | 01h\n"
+"\t; O_CREAT | O_TRUNC | O_WRONLY\n"
+"\tpush\tecx\n"
+"\tsys.open\n"
+"\tjc\terr\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1266
+#, no-wrap
+msgid ""
+"\tadd\tesp, byte 12\n"
+"\tmov\t[fd.out], eax\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1272
+#, no-wrap
+msgid ""
+".init:\n"
+"\tsub\teax, eax\n"
+"\tsub\tebx, ebx\n"
+"\tsub\tecx, ecx\n"
+"\tmov\tedi, obuffer\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1276
+#, no-wrap
+msgid ""
+".loop:\n"
+"\t; read a byte from input file or stdin\n"
+"\tcall\tgetchar\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1299
+#, no-wrap
+msgid ""
+".put:\n"
+"\tcall\tputchar\n"
+"\tcmp\tal, dl\n"
+"\tjne\t.loop\n"
+"\tcall\twrite\n"
+"\tjmp\tshort .loop\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1324
+#, no-wrap
+msgid ""
+"read:\n"
+"\tpush\tdword BUFSIZE\n"
+"\tmov\tesi, ibuffer\n"
+"\tpush\tesi\n"
+"\tpush\tdword [fd.in]\n"
+"\tsys.read\n"
+"\tadd\tesp, byte 12\n"
+"\tmov\tebx, eax\n"
+"\tor\teax, eax\n"
+"\tje\t.done\n"
+"\tsub\teax, eax\n"
+"\tret\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1328
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2561
+#, no-wrap
+msgid ""
+"align 4\n"
+".done:\n"
+"\tcall\twrite\t\t; flush output buffer\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1332
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2565
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3819
+#, no-wrap
+msgid ""
+"\t; close files\n"
+"\tpush\tdword [fd.in]\n"
+"\tsys.close\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1335
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2568
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3822
+#, no-wrap
+msgid ""
+"\tpush\tdword [fd.out]\n"
+"\tsys.close\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1339
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2572
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3828
+#, no-wrap
+msgid ""
+"\t; return success\n"
+"\tpush\tdword 0\n"
+"\tsys.exit\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1359
+#, no-wrap
+msgid ""
+"align 4\n"
+"write:\n"
+"\tsub\tedi, ecx\t; start of buffer\n"
+"\tpush\tecx\n"
+"\tpush\tedi\n"
+"\tpush\tdword [fd.out]\n"
+"\tsys.write\n"
+"\tadd\tesp, byte 12\n"
+"\tsub\teax, eax\n"
+"\tsub\tecx, ecx\t; buffer is empty now\n"
+"\tret\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1363
+msgid ""
+"In our `.data` section we now have two new variables, `fd.in` and `fd.out`. "
+"We store the input and output file descriptors here."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1365
+msgid ""
+"In the `.text` section we have replaced the references to `stdin` and "
+"`stdout` with `[fd.in]` and `[fd.out]`."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1368
+msgid ""
+"The `.text` section now starts with a simple error handler, which does "
+"nothing but exit the program with a return value of `1`. The error handler "
+"is before `_start` so we are within a short distance from where the errors "
+"occur."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1371
+msgid ""
+"Naturally, the program execution still begins at `_start`. First, we remove "
+"`argc` and `argv[0]` from the stack: They are of no interest to us (in this "
+"program, that is)."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1377
+msgid ""
+"We pop `argv[1]` to `ECX`. This register is particularly suited for "
+"pointers, as we can handle NULL pointers with `jecxz`. If `argv[1]` is not "
+"NULL, we try to open the file named in the first argument. Otherwise, we "
+"continue the program as before: Reading from `stdin`, writing to `stdout`. "
+"If we fail to open the input file (e.g., it does not exist), we jump to the "
+"error handler and quit."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1382
+msgid ""
+"If all went well, we now check for the second argument. If it is there, we "
+"open the output file. Otherwise, we send the output to `stdout`. If we "
+"fail to open the output file (e.g., it exists and we do not have the write "
+"permission), we, again, jump to the error handler."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1384
+msgid ""
+"The rest of the code is the same as before, except we close the input and "
+"output files before exiting, and, as mentioned, we use `[fd.in]` and `[fd."
+"out]`."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1386
+msgid "Our executable is now a whopping 768 bytes long."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1389
+msgid ""
+"Can we still improve it? Of course! Every program can be improved. Here are "
+"a few ideas of what we could do:"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1391
+msgid "Have our error handler print a message to `stderr`."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1392
+msgid "Add error handlers to the `read` and `write` functions."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1393
+msgid ""
+"Close `stdin` when we open an input file, `stdout` when we open an output "
+"file."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1394
+msgid ""
+"Add command line switches, such as `-i` and `-o`, so we can list the input "
+"and output files in any order, or perhaps read from `stdin` and write to a "
+"file."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1395
+msgid "Print a usage message if command line arguments are incorrect."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1397
+msgid ""
+"I shall leave these enhancements as an exercise to the reader: You already "
+"know everything you need to know to implement them."
+msgstr ""
+
+#. type: Title ==
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1399
+#, no-wrap
+msgid "UNIX(R) Environment"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1403
+msgid ""
+"An important UNIX(R) concept is the environment, which is defined by "
+"_environment variables_. Some are set by the system, others by you, yet "
+"others by the shell, or any program that loads another program."
+msgstr ""
+
+#. type: Title ===
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1405
+#, no-wrap
+msgid "How to Find Environment Variables"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1410
+msgid ""
+"I said earlier that when a program starts executing, the stack contains "
+"`argc` followed by the NULL-terminated `argv` array, followed by something "
+"else. The \"something else\" is the _environment_, or, to be more precise, "
+"a NULL-terminated array of pointers to _environment variables_. This is "
+"often referred to as `env`."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1413
+msgid ""
+"The structure of `env` is the same as that of `argv`, a list of memory "
+"addresses followed by a NULL (`0`). In this case, there is no `\"envc\"`-we "
+"figure out where the array ends by searching for the final NULL."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1416
+msgid ""
+"The variables usually come in the `name=value` format, but sometimes the "
+"`=value` part may be missing. We need to account for that possibility."
+msgstr ""
+
+#. type: Title ===
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1418
+#, no-wrap
+msgid "webvars"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1422
+msgid ""
+"I could just show you some code that prints the environment the same way the "
+"UNIX(R) env command does. But I thought it would be more interesting to "
+"write a simple assembly language CGI utility."
+msgstr ""
+
+#. type: Title ====
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1424
+#, no-wrap
+msgid "CGI: a Quick Overview"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1427
+msgid ""
+"I have a http://www.whizkidtech.redprince.net/cgi-bin/tutorial[detailed CGI "
+"tutorial] on my web site, but here is a very quick overview of CGI:"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1429
+msgid ""
+"The web server communicates with the CGI program by setting _environment "
+"variables_."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1430
+msgid ""
+"The CGI program sends its output to [.filename]#stdout#. The web server "
+"reads it from there."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1431
+msgid "It must start with an HTTP header followed by two blank lines."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1432
+msgid ""
+"It then prints the HTML code, or whatever other type of data it is producing."
+msgstr ""
+
+#. type: delimited block = 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1437
+msgid ""
+"While certain _environment variables_ use standard names, others vary, "
+"depending on the web server. That makes webvars quite a useful diagnostic "
+"tool."
+msgstr ""
+
+#. type: Title ====
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1440
+#, no-wrap
+msgid "The Code"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1444
+msgid ""
+"Our webvars program, then, must send out the HTTP header followed by some "
+"HTML mark-up. It then must read the _environment variables_ one by one and "
+"send them out as part of the HTML page."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1447
+msgid ""
+"The code follows. I placed comments and explanations right inside the code:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1484
+#, no-wrap
+msgid ""
+";;;;;;; webvars.asm ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n"
+";\n"
+"; Copyright (c) 2000 G. Adam Stanislav\n"
+"; All rights reserved.\n"
+";\n"
+"; Redistribution and use in source and binary forms, with or without\n"
+"; modification, are permitted provided that the following conditions\n"
+"; are met:\n"
+"; 1. Redistributions of source code must retain the above copyright\n"
+"; notice, this list of conditions and the following disclaimer.\n"
+"; 2. Redistributions in binary form must reproduce the above copyright\n"
+"; notice, this list of conditions and the following disclaimer in the\n"
+"; documentation and/or other materials provided with the distribution.\n"
+";\n"
+"; THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n"
+"; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n"
+"; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n"
+"; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n"
+"; FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n"
+"; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n"
+"; OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n"
+"; HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n"
+"; LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n"
+"; OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n"
+"; SUCH DAMAGE.\n"
+";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n"
+";\n"
+"; Version 1.0\n"
+";\n"
+"; Started:\t 8-Dec-2000\n"
+"; Updated:\t 8-Dec-2000\n"
+";\n"
+";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n"
+"%include\t'system.inc'\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1521
+#, no-wrap
+msgid ""
+"section\t.data\n"
+"http\tdb\t'Content-type: text/html', 0Ah, 0Ah\n"
+"\tdb\t'<?xml version=\"1.0\" encoding=\"utf-8\"?>', 0Ah\n"
+"\tdb\t'<!DOCTYPE html PUBLIC \"-//W3C/DTD XHTML Strict//EN\" '\n"
+"\tdb\t'\"DTD/xhtml1-strict.dtd\">', 0Ah\n"
+"\tdb\t'<html xmlns=\"http://www.w3.org/1999/xhtml\" '\n"
+"\tdb\t'xml.lang=\"en\" lang=\"en\">', 0Ah\n"
+"\tdb\t'<head>', 0Ah\n"
+"\tdb\t'<title>Web Environment</title>', 0Ah\n"
+"\tdb\t'<meta name=\"author\" content=\"G. Adam Stanislav\" />', 0Ah\n"
+"\tdb\t'</head>', 0Ah, 0Ah\n"
+"\tdb\t'<body bgcolor=\"#ffffff\" text=\"#000000\" link=\"#0000ff\" '\n"
+"\tdb\t'vlink=\"#840084\" alink=\"#0000ff\">', 0Ah\n"
+"\tdb\t'<div class=\"webvars\">', 0Ah\n"
+"\tdb\t'<h1>Web Environment</h1>', 0Ah\n"
+"\tdb\t'<p>The following <b>environment variables</b> are defined '\n"
+"\tdb\t'on this web server:</p>', 0Ah, 0Ah\n"
+"\tdb\t'<table align=\"center\" width=\"80\" border=\"0\" cellpadding=\"10\" '\n"
+"\tdb\t'cellspacing=\"0\" class=\"webvars\">', 0Ah\n"
+"httplen\tequ\t$-http\n"
+"left\tdb\t'<tr>', 0Ah\n"
+"\tdb\t'<td class=\"name\"><tt>'\n"
+"leftlen\tequ\t$-left\n"
+"middle\tdb\t'</tt></td>', 0Ah\n"
+"\tdb\t'<td class=\"value\"><tt><b>'\n"
+"midlen\tequ\t$-middle\n"
+"undef\tdb\t'<i>(undefined)</i>'\n"
+"undeflen\tequ\t$-undef\n"
+"right\tdb\t'</b></tt></td>', 0Ah\n"
+"\tdb\t'</tr>', 0Ah\n"
+"rightlen\tequ\t$-right\n"
+"wrap\tdb\t'</table>', 0Ah\n"
+"\tdb\t'</div>', 0Ah\n"
+"\tdb\t'</body>', 0Ah\n"
+"\tdb\t'</html>', 0Ah, 0Ah\n"
+"wraplen\tequ\t$-wrap\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1531
+#, no-wrap
+msgid ""
+"section\t.text\n"
+"global\t_start\n"
+"_start:\n"
+"\t; First, send out all the http and xhtml stuff that is\n"
+"\t; needed before we start showing the environment\n"
+"\tpush\tdword httplen\n"
+"\tpush\tdword http\n"
+"\tpush\tdword stdout\n"
+"\tsys.write\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1535
+#, no-wrap
+msgid ""
+"\t; Now find how far on the stack the environment pointers\n"
+"\t; are. We have 12 bytes we have pushed before \"argc\"\n"
+"\tmov\teax, [esp+12]\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1550
+#, no-wrap
+msgid ""
+"\t; We need to remove the following from the stack:\n"
+"\t;\n"
+"\t;\tThe 12 bytes we pushed for sys.write\n"
+"\t;\tThe 4 bytes of argc\n"
+"\t;\tThe EAX*4 bytes of argv\n"
+"\t;\tThe 4 bytes of the NULL after argv\n"
+"\t;\n"
+"\t; Total:\n"
+"\t;\t20 + eax * 4\n"
+"\t;\n"
+"\t; Because stack grows down, we need to ADD that many bytes\n"
+"\t; to ESP.\n"
+"\tlea\tesp, [esp+20+eax*4]\n"
+"\tcld\t\t; This should already be the case, but let's be sure.\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1556
+#, no-wrap
+msgid ""
+"\t; Loop through the environment, printing it out\n"
+".loop:\n"
+"\tpop\tedi\n"
+"\tor\tedi, edi\t; Done yet?\n"
+"\tje\tnear .wrap\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1562
+#, no-wrap
+msgid ""
+"\t; Print the left part of HTML\n"
+"\tpush\tdword leftlen\n"
+"\tpush\tdword left\n"
+"\tpush\tdword stdout\n"
+"\tsys.write\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1573
+#, no-wrap
+msgid ""
+"\t; It may be tempting to search for the '=' in the env string next.\n"
+"\t; But it is possible there is no '=', so we search for the\n"
+"\t; terminating NUL first.\n"
+"\tmov\tesi, edi\t; Save start of string\n"
+"\tsub\tecx, ecx\n"
+"\tnot\tecx\t\t; ECX = FFFFFFFF\n"
+"\tsub\teax, eax\n"
+"repne\tscasb\n"
+"\tnot\tecx\t\t; ECX = string length + 1\n"
+"\tmov\tebx, ecx\t; Save it in EBX\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1580
+#, no-wrap
+msgid ""
+"\t; Now is the time to find '='\n"
+"\tmov\tedi, esi\t; Start of string\n"
+"\tmov\tal, '='\n"
+"repne\tscasb\n"
+"\tnot\tecx\n"
+"\tadd\tecx, ebx\t; Length of name\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1585
+#, no-wrap
+msgid ""
+"\tpush\tecx\n"
+"\tpush\tesi\n"
+"\tpush\tdword stdout\n"
+"\tsys.write\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1591
+#, no-wrap
+msgid ""
+"\t; Print the middle part of HTML table code\n"
+"\tpush\tdword midlen\n"
+"\tpush\tdword middle\n"
+"\tpush\tdword stdout\n"
+"\tsys.write\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1595
+#, no-wrap
+msgid ""
+"\t; Find the length of the value\n"
+"\tnot\tecx\n"
+"\tlea\tebx, [ebx+ecx-1]\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1599
+#, no-wrap
+msgid ""
+"\t; Print \"undefined\" if 0\n"
+"\tor\tebx, ebx\n"
+"\tjne\t.value\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1602
+#, no-wrap
+msgid ""
+"\tmov\tebx, undeflen\n"
+"\tmov\tedi, undef\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1608
+#, no-wrap
+msgid ""
+".value:\n"
+"\tpush\tebx\n"
+"\tpush\tedi\n"
+"\tpush\tdword stdout\n"
+"\tsys.write\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1614
+#, no-wrap
+msgid ""
+"\t; Print the right part of the table row\n"
+"\tpush\tdword rightlen\n"
+"\tpush\tdword right\n"
+"\tpush\tdword stdout\n"
+"\tsys.write\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1617
+#, no-wrap
+msgid ""
+"\t; Get rid of the 60 bytes we have pushed\n"
+"\tadd\tesp, byte 60\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1620
+#, no-wrap
+msgid ""
+"\t; Get the next variable\n"
+"\tjmp\t.loop\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1627
+#, no-wrap
+msgid ""
+".wrap:\n"
+"\t; Print the rest of HTML\n"
+"\tpush\tdword wraplen\n"
+"\tpush\tdword wrap\n"
+"\tpush\tdword stdout\n"
+"\tsys.write\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1631
+#, no-wrap
+msgid ""
+"\t; Return success\n"
+"\tpush\tdword 0\n"
+"\tsys.exit\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1635
+msgid ""
+"This code produces a 1,396-byte executable. Most of it is data, i.e., the "
+"HTML mark-up we need to send out."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1637
+msgid "Assemble and link it as usual:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1642
+#, no-wrap
+msgid ""
+"% nasm -f elf webvars.asm\n"
+"% ld -s -o webvars webvars.o\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1646
+msgid ""
+"To use it, you need to upload [.filename]#webvars# to your web server. "
+"Depending on how your web server is set up, you may have to store it in a "
+"special [.filename]#cgi-bin# directory, or perhaps rename it with a [."
+"filename]#.cgi# extension."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1650
+msgid ""
+"Then you need to use your browser to view its output. To see its output on "
+"my web server, please go to http://www.int80h.org/webvars/[http://www.int80h."
+"org/webvars/]. If curious about the additional environment variables "
+"present in a password protected web directory, go to http://www.int80h.org/"
+"private/[http://www.int80h.org/private/], using the name `asm` and password "
+"`programmer`."
+msgstr ""
+
+#. type: Title ==
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1652
+#, no-wrap
+msgid "Working with Files"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1657
+msgid ""
+"We have already done some basic file work: We know how to open and close "
+"them, how to read and write them using buffers. But UNIX(R) offers much "
+"more functionality when it comes to files. We will examine some of it in "
+"this section, and end up with a nice file conversion utility."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1660
+msgid ""
+"Indeed, let us start at the end, that is, with the file conversion utility. "
+"It always makes programming easier when we know from the start what the end "
+"product is supposed to do."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1666
+msgid ""
+"One of the first programs I wrote for UNIX(R) was link:ftp://ftp.int80h.org/"
+"unix/tuc/[tuc], a text-to-UNIX(R) file converter. It converts a text file "
+"from other operating systems to a UNIX(R) text file. In other words, it "
+"changes from different kind of line endings to the newline convention of "
+"UNIX(R). It saves the output in a different file. Optionally, it converts "
+"a UNIX(R) text file to a DOS text file."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1670
+msgid ""
+"I have used tuc extensively, but always only to convert from some other OS "
+"to UNIX(R), never the other way. I have always wished it would just "
+"overwrite the file instead of me having to send the output to a different "
+"file. Most of the time, I end up using it like this:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1675
+#, no-wrap
+msgid ""
+"% tuc myfile tempfile\n"
+"% mv tempfile myfile\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1678
+msgid ""
+"It would be nice to have a ftuc, i.e., _fast tuc_, and use it like this:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1682
+#, no-wrap
+msgid "% ftuc myfile\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1685
+msgid ""
+"In this chapter, then, we will write ftuc in assembly language (the original "
+"tuc is in C), and study various file-oriented kernel services in the process."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1687
+msgid ""
+"At first sight, such a file conversion is very simple: All you have to do is "
+"strip the carriage returns, right?"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1689
+msgid ""
+"If you answered yes, think again: That approach will work most of the time "
+"(at least with MS DOS text files), but will fail occasionally."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1694
+msgid ""
+"The problem is that not all non UNIX(R) text files end their line with the "
+"carriage return / line feed sequence. Some use carriage returns without "
+"line feeds. Others combine several blank lines into a single carriage "
+"return followed by several line feeds. And so on."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1696
+msgid ""
+"A text file converter, then, must be able to handle any possible line "
+"endings:"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1698
+msgid "carriage return / line feed"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1699
+msgid "carriage return"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1700
+msgid "line feed / carriage return"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1701
+msgid "line feed"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1703
+msgid ""
+"It should also handle files that use some kind of a combination of the above "
+"(e.g., carriage return followed by several line feeds)."
+msgstr ""
+
+#. type: Title ===
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1705
+#, no-wrap
+msgid "Finite State Machine"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1712
+msgid ""
+"The problem is easily solved by the use of a technique called _finite state "
+"machine_, originally developed by the designers of digital electronic "
+"circuits. A _finite state machine_ is a digital circuit whose output is "
+"dependent not only on its input but on its previous input, i.e., on its "
+"state. The microprocessor is an example of a _finite state machine_: Our "
+"assembly language code is assembled to machine language in which some "
+"assembly language code produces a single byte of machine language, while "
+"others produce several bytes. As the microprocessor fetches the bytes from "
+"the memory one by one, some of them simply change its state rather than "
+"produce some output. When all the bytes of the op code are fetched, the "
+"microprocessor produces some output, or changes the value of a register, etc."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1715
+msgid ""
+"Because of that, all software is essentially a sequence of state "
+"instructions for the microprocessor. Nevertheless, the concept of _finite "
+"state machine_ is useful in software design as well."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1718
+msgid ""
+"Our text file converter can be designer as a _finite state machine_ with "
+"three possible states. We could call them states 0-2, but it will make our "
+"life easier if we give them symbolic names:"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1720
+msgid "ordinary"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1721
+msgid "cr"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1722
+msgid "lf"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1724
+msgid ""
+"Our program will start in the ordinary state. During this state, the program "
+"action depends on its input as follows:"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1727
+msgid ""
+"If the input is anything other than a carriage return or line feed, the "
+"input is simply passed on to the output. The state remains unchanged."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1729
+msgid ""
+"If the input is a carriage return, the state is changed to cr. The input is "
+"then discarded, i.e., no output is made."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1731
+msgid ""
+"If the input is a line feed, the state is changed to lf. The input is then "
+"discarded."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1734
+msgid ""
+"Whenever we are in the cr state, it is because the last input was a carriage "
+"return, which was unprocessed. What our software does in this state again "
+"depends on the current input:"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1736
+msgid ""
+"If the input is anything other than a carriage return or line feed, output a "
+"line feed, then output the input, then change the state to ordinary."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1737
+msgid ""
+"If the input is a carriage return, we have received two (or more) carriage "
+"returns in a row. We discard the input, we output a line feed, and leave the "
+"state unchanged."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1738
+msgid ""
+"If the input is a line feed, we output the line feed and change the state to "
+"ordinary. Note that this is not the same as the first case above - if we "
+"tried to combine them, we would be outputting two line feeds instead of one."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1742
+msgid ""
+"Finally, we are in the lf state after we have received a line feed that was "
+"not preceded by a carriage return. This will happen when our file already "
+"is in UNIX(R) format, or whenever several lines in a row are expressed by a "
+"single carriage return followed by several line feeds, or when line ends "
+"with a line feed / carriage return sequence. Here is how we need to handle "
+"our input in this state:"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1744
+msgid ""
+"If the input is anything other than a carriage return or line feed, we "
+"output a line feed, then output the input, then change the state to "
+"ordinary. This is exactly the same action as in the cr state upon receiving "
+"the same kind of input."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1745
+msgid ""
+"If the input is a carriage return, we discard the input, we output a line "
+"feed, then change the state to ordinary."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1746
+msgid ""
+"If the input is a line feed, we output the line feed, and leave the state "
+"unchanged."
+msgstr ""
+
+#. type: Title ====
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1748
+#, no-wrap
+msgid "The Final State"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1753
+msgid ""
+"The above _finite state machine_ works for the entire file, but leaves the "
+"possibility that the final line end will be ignored. That will happen "
+"whenever the file ends with a single carriage return or a single line feed. "
+"I did not think of it when I wrote tuc, just to discover that occasionally "
+"it strips the last line ending."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1756
+msgid ""
+"This problem is easily fixed by checking the state after the entire file was "
+"processed. If the state is not ordinary, we simply need to output one last "
+"line feed."
+msgstr ""
+
+#. type: delimited block = 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1762
+msgid ""
+"Now that we have expressed our algorithm as a _finite state machine_, we "
+"could easily design a dedicated digital electronic circuit (a \"chip\") to "
+"do the conversion for us. Of course, doing so would be considerably more "
+"expensive than writing an assembly language program."
+msgstr ""
+
+#. type: Title ====
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1765
+#, no-wrap
+msgid "The Output Counter"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1770
+msgid ""
+"Because our file conversion program may be combining two characters into "
+"one, we need to use an output counter. We initialize it to `0`, and "
+"increase it every time we send a character to the output. At the end of the "
+"program, the counter will tell us what size we need to set the file to."
+msgstr ""
+
+#. type: Title ===
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1772
+#, no-wrap
+msgid "Implementing FSM in Software"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1776
+msgid ""
+"The hardest part of working with a _finite state machine_ is analyzing the "
+"problem and expressing it as a _finite state machine_. That accomplished, "
+"the software almost writes itself."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1779
+msgid ""
+"In a high-level language, such as C, there are several main approaches. One "
+"is to use a `switch` statement which chooses what function should be run. "
+"For example,"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1794
+#, no-wrap
+msgid ""
+"switch (state) {\n"
+"\tdefault:\n"
+"\tcase REGULAR:\n"
+"\t\tregular(inputchar);\n"
+"\t\tbreak;\n"
+"\tcase CR:\n"
+"\t\tcr(inputchar);\n"
+"\t\tbreak;\n"
+"\tcase LF:\n"
+"\t\tlf(inputchar);\n"
+"\t\tbreak;\n"
+"\t}\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1797
+msgid ""
+"Another approach is by using an array of function pointers, something like "
+"this:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1801
+#, no-wrap
+msgid "(output[state])(inputchar);\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1804
+msgid ""
+"Yet another is to have `state` be a function pointer, set to point at the "
+"appropriate function:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1808
+#, no-wrap
+msgid "(*state)(inputchar);\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1812
+msgid ""
+"This is the approach we will use in our program because it is very easy to "
+"do in assembly language, and very fast, too. We will simply keep the "
+"address of the right procedure in `EBX`, and then just issue:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1816
+#, no-wrap
+msgid "call\tebx\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1820
+msgid ""
+"This is possibly faster than hardcoding the address in the code because the "
+"microprocessor does not have to fetch the address from the memory-it is "
+"already stored in one of its registers. I said _possibly_ because with the "
+"caching modern microprocessors do, either way may be equally fast."
+msgstr ""
+
+#. type: Title ===
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1822
+#, no-wrap
+msgid "Memory Mapped Files"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1826
+msgid ""
+"Because our program works on a single file, we cannot use the approach that "
+"worked for us before, i.e., to read from an input file and to write to an "
+"output file."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1834
+msgid ""
+"UNIX(R) allows us to map a file, or a section of a file, into memory. To do "
+"that, we first need to open the file with the appropriate read/write flags. "
+"Then we use the `mmap` system call to map it into the memory. One nice "
+"thing about `mmap` is that it automatically works with virtual memory: We "
+"can map more of the file into the memory than we have physical memory "
+"available, yet still access it through regular memory op codes, such as "
+"`mov`, `lods`, and `stos`. Whatever changes we make to the memory image of "
+"the file will be written to the file by the system. We do not even have to "
+"keep the file open: As long as it stays mapped, we can read from it and "
+"write to it."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1837
+msgid ""
+"The 32-bit Intel microprocessors can access up to four gigabytes of memory - "
+"physical or virtual. The FreeBSD system allows us to use up to a half of it "
+"for file mapping."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1841
+msgid ""
+"For simplicity sake, in this tutorial we will only convert files that can be "
+"mapped into the memory in their entirety. There are probably not too many "
+"text files that exceed two gigabytes in size. If our program encounters "
+"one, it will simply display a message suggesting we use the original tuc "
+"instead."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1847
+msgid ""
+"If you examine your copy of [.filename]#syscalls.master#, you will find two "
+"separate syscalls named `mmap`. This is because of evolution of UNIX(R): "
+"There was the traditional BSD `mmap`, syscall 71. That one was superseded "
+"by the POSIX(R) `mmap`, syscall 197. The FreeBSD system supports both "
+"because older programs were written by using the original BSD version. But "
+"new software uses the POSIX(R) version, which is what we will use."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1849
+msgid "The [.filename]#syscalls.master# lists the POSIX(R) version like this:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1854
+#, no-wrap
+msgid ""
+"197\tSTD\tBSD\t{ caddr_t mmap(caddr_t addr, size_t len, int prot, \\\n"
+"\t\t\t int flags, int fd, long pad, off_t pos); }\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1858
+msgid ""
+"This differs slightly from what man:mmap[2] says. That is because man:"
+"mmap[2] describes the C version."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1862
+msgid ""
+"The difference is in the `long pad` argument, which is not present in the C "
+"version. However, the FreeBSD syscalls add a 32-bit pad after ``push``ing a "
+"64-bit argument. In this case, `off_t` is a 64-bit value."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1864
+msgid ""
+"When we are finished working with a memory-mapped file, we unmap it with the "
+"`munmap` syscall:"
+msgstr ""
+
+#. type: delimited block = 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1868
+msgid ""
+"For an in-depth treatment of `mmap`, see W. Richard Stevens' http://www."
+"int80h.org/cgi-bin/isbn?isbn=0130810819[Unix Network Programming, Volume 2, "
+"Chapter 12]."
+msgstr ""
+
+#. type: Title ===
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1871
+#, no-wrap
+msgid "Determining File Size"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1874
+msgid ""
+"Because we need to tell `mmap` how many bytes of the file to map into the "
+"memory, and because we want to map the entire file, we need to determine the "
+"size of the file."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1877
+msgid ""
+"We can use the `fstat` syscall to get all the information about an open file "
+"that the system can give us. That includes the file size."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1880
+msgid ""
+"Again, [.filename]#syscalls.master# lists two versions of `fstat`, a "
+"traditional one (syscall 62), and a POSIX(R) one (syscall 189). Naturally, "
+"we will use the POSIX(R) version:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1884
+#, no-wrap
+msgid "189\tSTD\tPOSIX\t{ int fstat(int fd, struct stat *sb); }\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1888
+msgid ""
+"This is a very straightforward call: We pass to it the address of a `stat` "
+"structure and the descriptor of an open file. It will fill out the contents "
+"of the `stat` structure."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1891
+msgid ""
+"I do, however, have to say that I tried to declare the `stat` structure in "
+"the `.bss` section, and `fstat` did not like it: It set the carry flag "
+"indicating an error. After I changed the code to allocate the structure on "
+"the stack, everything was working fine."
+msgstr ""
+
+#. type: Title ===
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1893
+#, no-wrap
+msgid "Changing the File Size"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1897
+msgid ""
+"Because our program may combine carriage return / line feed sequences into "
+"straight line feeds, our output may be smaller than our input. However, "
+"since we are placing our output into the same file we read the input from, "
+"we may have to change the size of the file."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1900
+msgid ""
+"The `ftruncate` system call allows us to do just that. Despite its somewhat "
+"misleading name, the `ftruncate` system call can be used to both truncate "
+"the file (make it smaller) and to grow it."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1903
+msgid ""
+"And yes, we will find two versions of `ftruncate` in [.filename]#syscalls."
+"master#, an older one (130), and a newer one (201). We will use the newer "
+"one:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1907
+#, no-wrap
+msgid "201\tSTD\tBSD\t{ int ftruncate(int fd, int pad, off_t length); }\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1910
+msgid "Please note that this one contains a `int pad` again."
+msgstr ""
+
+#. type: Title ===
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1912
+#, no-wrap
+msgid "ftuc"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1917
+msgid ""
+"We now know everything we need to write ftuc. We start by adding some new "
+"lines in [.filename]#system.inc#. First, we define some constants and "
+"structures, somewhere at or near the beginning of the file:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1924
+#, no-wrap
+msgid ""
+";;;;;;; open flags\n"
+"%define\tO_RDONLY\t0\n"
+"%define\tO_WRONLY\t1\n"
+"%define\tO_RDWR\t2\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1933
+#, no-wrap
+msgid ""
+";;;;;;; mmap flags\n"
+"%define\tPROT_NONE\t0\n"
+"%define\tPROT_READ\t1\n"
+"%define\tPROT_WRITE\t2\n"
+"%define\tPROT_EXEC\t4\n"
+";;\n"
+"%define\tMAP_SHARED\t0001h\n"
+"%define\tMAP_PRIVATE\t0002h\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1957
+#, no-wrap
+msgid ""
+";;;;;;; stat structure\n"
+"struc\tstat\n"
+"st_dev\t\tresd\t1\t; = 0\n"
+"st_ino\t\tresd\t1\t; = 4\n"
+"st_mode\t\tresw\t1\t; = 8, size is 16 bits\n"
+"st_nlink\tresw\t1\t; = 10, ditto\n"
+"st_uid\t\tresd\t1\t; = 12\n"
+"st_gid\t\tresd\t1\t; = 16\n"
+"st_rdev\t\tresd\t1\t; = 20\n"
+"st_atime\tresd\t1\t; = 24\n"
+"st_atimensec\tresd\t1\t; = 28\n"
+"st_mtime\tresd\t1\t; = 32\n"
+"st_mtimensec\tresd\t1\t; = 36\n"
+"st_ctime\tresd\t1\t; = 40\n"
+"st_ctimensec\tresd\t1\t; = 44\n"
+"st_size\t\tresd\t2\t; = 48, size is 64 bits\n"
+"st_blocks\tresd\t2\t; = 56, ditto\n"
+"st_blksize\tresd\t1\t; = 64\n"
+"st_flags\tresd\t1\t; = 68\n"
+"st_gen\t\tresd\t1\t; = 72\n"
+"st_lspare\tresd\t1\t; = 76\n"
+"st_qspare\tresd\t4\t; = 80\n"
+"endstruc\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1960
+msgid "We define the new syscalls:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1967
+#, no-wrap
+msgid ""
+"%define\tSYS_mmap\t197\n"
+"%define\tSYS_munmap\t73\n"
+"%define\tSYS_fstat\t189\n"
+"%define\tSYS_ftruncate\t201\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1970
+msgid "We add the macros for their use:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1976
+#, no-wrap
+msgid ""
+"%macro\tsys.mmap\t0\n"
+"\tsystem\tSYS_mmap\n"
+"%endmacro\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1980
+#, no-wrap
+msgid ""
+"%macro\tsys.munmap\t0\n"
+"\tsystem\tSYS_munmap\n"
+"%endmacro\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1984
+#, no-wrap
+msgid ""
+"%macro\tsys.ftruncate\t0\n"
+"\tsystem\tSYS_ftruncate\n"
+"%endmacro\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1988
+#, no-wrap
+msgid ""
+"%macro\tsys.fstat\t0\n"
+"\tsystem\tSYS_fstat\n"
+"%endmacro\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:1991
+msgid "And here is our code:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2004
+#, no-wrap
+msgid ""
+";;;;;;; Fast Text-to-Unix Conversion (ftuc.asm) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n"
+";;\n"
+";; Started:\t21-Dec-2000\n"
+";; Updated:\t22-Dec-2000\n"
+";;\n"
+";; Copyright 2000 G. Adam Stanislav.\n"
+";; All rights reserved.\n"
+";;\n"
+";;;;;;; v.1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n"
+"%include\t'system.inc'\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2018
+#, no-wrap
+msgid ""
+"section\t.data\n"
+"\tdb\t'Copyright 2000 G. Adam Stanislav.', 0Ah\n"
+"\tdb\t'All rights reserved.', 0Ah\n"
+"usg\tdb\t'Usage: ftuc filename', 0Ah\n"
+"usglen\tequ\t$-usg\n"
+"co\tdb\t\"ftuc: Can't open file.\", 0Ah\n"
+"colen\tequ\t$-co\n"
+"fae\tdb\t'ftuc: File access error.', 0Ah\n"
+"faelen\tequ\t$-fae\n"
+"ftl\tdb\t'ftuc: File too long, use regular tuc instead.', 0Ah\n"
+"ftllen\tequ\t$-ftl\n"
+"mae\tdb\t'ftuc: Memory allocation error.', 0Ah\n"
+"maelen\tequ\t$-mae\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2020
+#, no-wrap
+msgid "section\t.text\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2026
+#, no-wrap
+msgid ""
+"align 4\n"
+"memerr:\n"
+"\tpush\tdword maelen\n"
+"\tpush\tdword mae\n"
+"\tjmp\tshort error\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2032
+#, no-wrap
+msgid ""
+"align 4\n"
+"toolong:\n"
+"\tpush\tdword ftllen\n"
+"\tpush\tdword ftl\n"
+"\tjmp\tshort error\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2038
+#, no-wrap
+msgid ""
+"align 4\n"
+"facerr:\n"
+"\tpush\tdword faelen\n"
+"\tpush\tdword fae\n"
+"\tjmp\tshort error\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2044
+#, no-wrap
+msgid ""
+"align 4\n"
+"cantopen:\n"
+"\tpush\tdword colen\n"
+"\tpush\tdword co\n"
+"\tjmp\tshort error\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2049
+#, no-wrap
+msgid ""
+"align 4\n"
+"usage:\n"
+"\tpush\tdword usglen\n"
+"\tpush\tdword usg\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2053
+#, no-wrap
+msgid ""
+"error:\n"
+"\tpush\tdword stderr\n"
+"\tsys.write\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2056
+#, no-wrap
+msgid ""
+"\tpush\tdword 1\n"
+"\tsys.exit\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2064
+#, no-wrap
+msgid ""
+"align 4\n"
+"global\t_start\n"
+"_start:\n"
+"\tpop\teax\t\t; argc\n"
+"\tpop\teax\t\t; program name\n"
+"\tpop\tecx\t\t; file to convert\n"
+"\tjecxz\tusage\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2068
+#, no-wrap
+msgid ""
+"\tpop\teax\n"
+"\tor\teax, eax\t; Too many arguments?\n"
+"\tjne\tusage\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2074
+#, no-wrap
+msgid ""
+"\t; Open the file\n"
+"\tpush\tdword O_RDWR\n"
+"\tpush\tecx\n"
+"\tsys.open\n"
+"\tjc\tcantopen\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2076
+#, no-wrap
+msgid "\tmov\tebp, eax\t; Save fd\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2079
+#, no-wrap
+msgid ""
+"\tsub\tesp, byte stat_size\n"
+"\tmov\tebx, esp\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2085
+#, no-wrap
+msgid ""
+"\t; Find file size\n"
+"\tpush\tebx\n"
+"\tpush\tebp\t\t; fd\n"
+"\tsys.fstat\n"
+"\tjc\tfacerr\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2087
+#, no-wrap
+msgid "\tmov\tedx, [ebx + st_size + 4]\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2095
+#, no-wrap
+msgid ""
+"\t; File is too long if EDX != 0 ...\n"
+"\tor\tedx, edx\n"
+"\tjne\tnear toolong\n"
+"\tmov\tecx, [ebx + st_size]\n"
+"\t; ... or if it is above 2 GB\n"
+"\tor\tecx, ecx\n"
+"\tjs\tnear toolong\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2098
+#, no-wrap
+msgid ""
+"\t; Do nothing if the file is 0 bytes in size\n"
+"\tjecxz\t.quit\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2110
+#, no-wrap
+msgid ""
+"\t; Map the entire file in memory\n"
+"\tpush\tedx\n"
+"\tpush\tedx\t\t; starting at offset 0\n"
+"\tpush\tedx\t\t; pad\n"
+"\tpush\tebp\t\t; fd\n"
+"\tpush\tdword MAP_SHARED\n"
+"\tpush\tdword PROT_READ | PROT_WRITE\n"
+"\tpush\tecx\t\t; entire file size\n"
+"\tpush\tedx\t\t; let system decide on the address\n"
+"\tsys.mmap\n"
+"\tjc\tnear memerr\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2115
+#, no-wrap
+msgid ""
+"\tmov\tedi, eax\n"
+"\tmov\tesi, eax\n"
+"\tpush\tecx\t\t; for SYS_munmap\n"
+"\tpush\tedi\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2120
+#, no-wrap
+msgid ""
+"\t; Use EBX for state machine\n"
+"\tmov\tebx, ordinary\n"
+"\tmov\tah, 0Ah\n"
+"\tcld\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2125
+#, no-wrap
+msgid ""
+".loop:\n"
+"\tlodsb\n"
+"\tcall\tebx\n"
+"\tloop\t.loop\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2128
+#, no-wrap
+msgid ""
+"\tcmp\tebx, ordinary\n"
+"\tje\t.filesize\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2133
+#, no-wrap
+msgid ""
+"\t; Output final lf\n"
+"\tmov\tal, ah\n"
+"\tstosb\n"
+"\tinc\tedx\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2141
+#, no-wrap
+msgid ""
+".filesize:\n"
+"\t; truncate file to new size\n"
+"\tpush\tdword 0\t\t; high dword\n"
+"\tpush\tedx\t\t; low dword\n"
+"\tpush\teax\t\t; pad\n"
+"\tpush\tebp\n"
+"\tsys.ftruncate\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2144
+#, no-wrap
+msgid ""
+"\t; close it (ebp still pushed)\n"
+"\tsys.close\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2147
+#, no-wrap
+msgid ""
+"\tadd\tesp, byte 16\n"
+"\tsys.munmap\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2151
+#, no-wrap
+msgid ""
+".quit:\n"
+"\tpush\tdword 0\n"
+"\tsys.exit\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2156
+#, no-wrap
+msgid ""
+"align 4\n"
+"ordinary:\n"
+"\tcmp\tal, 0Dh\n"
+"\tje\t.cr\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2159
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2181
+#, no-wrap
+msgid ""
+"\tcmp\tal, ah\n"
+"\tje\t.lf\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2163
+#, no-wrap
+msgid ""
+"\tstosb\n"
+"\tinc\tedx\n"
+"\tret\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2168
+#, no-wrap
+msgid ""
+"align 4\n"
+".cr:\n"
+"\tmov\tebx, cr\n"
+"\tret\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2173
+#, no-wrap
+msgid ""
+"align 4\n"
+".lf:\n"
+"\tmov\tebx, lf\n"
+"\tret\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2178
+#, no-wrap
+msgid ""
+"align 4\n"
+"cr:\n"
+"\tcmp\tal, 0Dh\n"
+"\tje\t.cr\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2185
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2213
+#, no-wrap
+msgid ""
+"\txchg\tal, ah\n"
+"\tstosb\n"
+"\tinc\tedx\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2188
+#, no-wrap
+msgid ""
+"\txchg\tal, ah\n"
+"\t; fall through\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2194
+#, no-wrap
+msgid ""
+".lf:\n"
+"\tstosb\n"
+"\tinc\tedx\n"
+"\tmov\tebx, ordinary\n"
+"\tret\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2201
+#, no-wrap
+msgid ""
+"align 4\n"
+".cr:\n"
+"\tmov\tal, ah\n"
+"\tstosb\n"
+"\tinc\tedx\n"
+"\tret\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2206
+#, no-wrap
+msgid ""
+"align 4\n"
+"lf:\n"
+"\tcmp\tal, ah\n"
+"\tje\t.lf\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2209
+#, no-wrap
+msgid ""
+"\tcmp\tal, 0Dh\n"
+"\tje\t.cr\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2219
+#, no-wrap
+msgid ""
+"\txchg\tal, ah\n"
+"\tstosb\n"
+"\tinc\tedx\n"
+"\tmov\tebx, ordinary\n"
+"\tret\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2225
+#, no-wrap
+msgid ""
+"align 4\n"
+".cr:\n"
+"\tmov\tebx, ordinary\n"
+"\tmov\tal, ah\n"
+"\t; fall through\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2230
+#, no-wrap
+msgid ""
+".lf:\n"
+"\tstosb\n"
+"\tinc\tedx\n"
+"\tret\n"
+msgstr ""
+
+#. type: delimited block = 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2237
+msgid ""
+"Do not use this program on files stored on a disk formatted by MS-DOS(R) or "
+"Windows(R). There seems to be a subtle bug in the FreeBSD code when using "
+"`mmap` on these drives mounted under FreeBSD: If the file is over a certain "
+"size, `mmap` will just fill the memory with zeros, and then copy them to the "
+"file overwriting its contents."
+msgstr ""
+
+#. type: Title ==
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2240
+#, no-wrap
+msgid "One-Pointed Mind"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2243
+msgid ""
+"As a student of Zen, I like the idea of a one-pointed mind: Do one thing at "
+"a time, and do it well."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2246
+msgid ""
+"This, indeed, is very much how UNIX(R) works as well. While a typical "
+"Windows(R) application is attempting to do everything imaginable (and is, "
+"therefore, riddled with bugs), a typical UNIX(R) program does only one "
+"thing, and it does it well."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2248
+msgid ""
+"The typical UNIX(R) user then essentially assembles his own applications by "
+"writing a shell script which combines the various existing programs by "
+"piping the output of one program to the input of another."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2250
+msgid ""
+"When writing your own UNIX(R) software, it is generally a good idea to see "
+"what parts of the problem you need to solve can be handled by existing "
+"programs, and only write your own programs for that part of the problem that "
+"you do not have an existing solution for."
+msgstr ""
+
+#. type: Title ===
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2252
+#, no-wrap
+msgid "CSV"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2255
+msgid ""
+"I will illustrate this principle with a specific real-life example I was "
+"faced with recently:"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2259
+msgid ""
+"I needed to extract the 11th field of each record from a database I "
+"downloaded from a web site. The database was a CSV file, i.e., a list of "
+"_comma-separated values_. That is quite a standard format for sharing data "
+"among people who may be using different database software."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2262
+msgid ""
+"The first line of the file contains the list of various fields separated by "
+"commas. The rest of the file contains the data listed line by line, with "
+"values separated by commas."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2264
+msgid ""
+"I tried awk, using the comma as a separator. But because several lines "
+"contained a quoted comma, awk was extracting the wrong field from those "
+"lines."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2267
+msgid ""
+"Therefore, I needed to write my own software to extract the 11th field from "
+"the CSV file. However, going with the UNIX(R) spirit, I only needed to "
+"write a simple filter that would do the following:"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2269
+msgid "Remove the first line from the file;"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2270
+msgid "Change all unquoted commas to a different character;"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2271
+msgid "Remove all quotation marks."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2273
+msgid ""
+"Strictly speaking, I could use sed to remove the first line from the file, "
+"but doing so in my own program was very easy, so I decided to do it and "
+"reduce the size of the pipeline."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2277
+msgid ""
+"At any rate, writing a program like this took me about 20 minutes. Writing "
+"a program that extracts the 11th field from the CSV file would take a lot "
+"longer, and I could not reuse it to extract some other field from some other "
+"database."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2279
+msgid ""
+"This time I decided to let it do a little more work than a typical tutorial "
+"program would:"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2281
+msgid "It parses its command line for options;"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2282
+msgid "It displays proper usage if it finds wrong arguments;"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2283
+msgid "It produces meaningful error messages."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2285
+msgid "Here is its usage message:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2289
+#, no-wrap
+msgid "Usage: csv [-t<delim>] [-c<comma>] [-p] [-o <outfile>] [-i <infile>]\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2292
+msgid "All parameters are optional, and can appear in any order."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2296
+msgid ""
+"The `-t` parameter declares what to replace the commas with. The `tab` is "
+"the default here. For example, `-t;` will replace all unquoted commas with "
+"semicolons."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2300
+msgid ""
+"I did not need the `-c` option, but it may come in handy in the future. It "
+"lets me declare that I want a character other than a comma replaced with "
+"something else. For example, `-c@` will replace all at signs (useful if you "
+"want to split a list of email addresses to their user names and domains)."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2303
+msgid ""
+"The `-p` option preserves the first line, i.e., it does not delete it. By "
+"default, we delete the first line because in a CSV file it contains the "
+"field names rather than data."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2306
+msgid ""
+"The `-i` and `-o` options let me specify the input and the output files. "
+"Defaults are [.filename]#stdin# and [.filename]#stdout#, so this is a "
+"regular UNIX(R) filter."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2309
+msgid ""
+"I made sure that both `-i filename` and `-ifilename` are accepted. I also "
+"made sure that only one input and one output files may be specified."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2311
+msgid "To get the 11th field of each record, I can now do:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2315
+#, no-wrap
+msgid "% csv '-t;' data.csv | awk '-F;' '{print $11}'\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2318
+msgid ""
+"The code stores the options (except for the file descriptors) in `EDX`: The "
+"comma in `DH`, the new separator in `DL`, and the flag for the `-p` option "
+"in the highest bit of `EDX`, so a check for its sign will give us a quick "
+"decision what to do."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2320
+msgid "Here is the code:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2334
+#, no-wrap
+msgid ""
+";;;;;;; csv.asm ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n"
+";\n"
+"; Convert a comma-separated file to a something-else separated file.\n"
+";\n"
+"; Started:\t31-May-2001\n"
+"; Updated:\t 1-Jun-2001\n"
+";\n"
+"; Copyright (c) 2001 G. Adam Stanislav\n"
+"; All rights reserved.\n"
+";\n"
+";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2348
+#, no-wrap
+msgid ""
+"section\t.data\n"
+"fd.in\tdd\tstdin\n"
+"fd.out\tdd\tstdout\n"
+"usg\tdb\t'Usage: csv [-t<delim>] [-c<comma>] [-p] [-o <outfile>] [-i <infile>]', 0Ah\n"
+"usglen\tequ\t$-usg\n"
+"iemsg\tdb\t\"csv: Can't open input file\", 0Ah\n"
+"iemlen\tequ\t$-iemsg\n"
+"oemsg\tdb\t\"csv: Can't create output file\", 0Ah\n"
+"oemlen\tequ\t$-oemsg\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2362
+#, no-wrap
+msgid ""
+"section\t.text\n"
+"align 4\n"
+"ierr:\n"
+"\tpush\tdword iemlen\n"
+"\tpush\tdword iemsg\n"
+"\tpush\tdword stderr\n"
+"\tsys.write\n"
+"\tpush\tdword 1\t\t; return failure\n"
+"\tsys.exit\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2371
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3420
+#, no-wrap
+msgid ""
+"align 4\n"
+"oerr:\n"
+"\tpush\tdword oemlen\n"
+"\tpush\tdword oemsg\n"
+"\tpush\tdword stderr\n"
+"\tsys.write\n"
+"\tpush\tdword 2\n"
+"\tsys.exit\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2380
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3429
+#, no-wrap
+msgid ""
+"align 4\n"
+"usage:\n"
+"\tpush\tdword usglen\n"
+"\tpush\tdword usg\n"
+"\tpush\tdword stderr\n"
+"\tsys.write\n"
+"\tpush\tdword 3\n"
+"\tsys.exit\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2386
+#, no-wrap
+msgid ""
+"align 4\n"
+"global\t_start\n"
+"_start:\n"
+"\tadd\tesp, byte 8\t; discard argc and argv[0]\n"
+"\tmov\tedx, (',' << 8) | 9\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2391
+#, no-wrap
+msgid ""
+".arg:\n"
+"\tpop\tecx\n"
+"\tor\tecx, ecx\n"
+"\tje\tnear .init\t\t; no more arguments\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2395
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3444
+#, no-wrap
+msgid ""
+"\t; ECX contains the pointer to an argument\n"
+"\tcmp\tbyte [ecx], '-'\n"
+"\tjne\tusage\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2398
+#, no-wrap
+msgid ""
+"\tinc\tecx\n"
+"\tmov\tax, [ecx]\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2402
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3452
+#, no-wrap
+msgid ""
+".o:\n"
+"\tcmp\tal, 'o'\n"
+"\tjne\t.i\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2406
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3456
+#, no-wrap
+msgid ""
+"\t; Make sure we are not asked for the output file twice\n"
+"\tcmp\tdword [fd.out], stdout\n"
+"\tjne\tusage\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2411
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3461
+#, no-wrap
+msgid ""
+"\t; Find the path to output file - it is either at [ECX+1],\n"
+"\t; i.e., -ofile --\n"
+"\t; or in the next argument,\n"
+"\t; i.e., -o file\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2417
+#, no-wrap
+msgid ""
+"\tinc\tecx\n"
+"\tor\tah, ah\n"
+"\tjne\t.openoutput\n"
+"\tpop\tecx\n"
+"\tjecxz\tusage\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2425
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3474
+#, no-wrap
+msgid ""
+".openoutput:\n"
+"\tpush\tdword 420\t; file mode (644 octal)\n"
+"\tpush\tdword 0200h | 0400h | 01h\n"
+"\t; O_CREAT | O_TRUNC | O_WRONLY\n"
+"\tpush\tecx\n"
+"\tsys.open\n"
+"\tjc\tnear oerr\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2429
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3478
+#, no-wrap
+msgid ""
+"\tadd\tesp, byte 12\n"
+"\tmov\t[fd.out], eax\n"
+"\tjmp\tshort .arg\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2433
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3482
+#, no-wrap
+msgid ""
+".i:\n"
+"\tcmp\tal, 'i'\n"
+"\tjne\t.p\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2437
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3486
+#, no-wrap
+msgid ""
+"\t; Make sure we are not asked twice\n"
+"\tcmp\tdword [fd.in], stdin\n"
+"\tjne\tnear usage\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2445
+#, no-wrap
+msgid ""
+"\t; Find the path to the input file\n"
+"\tinc\tecx\n"
+"\tor\tah, ah\n"
+"\tjne\t.openinput\n"
+"\tpop\tecx\n"
+"\tor\tecx, ecx\n"
+"\tje near usage\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2451
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3499
+#, no-wrap
+msgid ""
+".openinput:\n"
+"\tpush\tdword 0\t\t; O_RDONLY\n"
+"\tpush\tecx\n"
+"\tsys.open\n"
+"\tjc\tnear ierr\t\t; open failed\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2455
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3503
+#, no-wrap
+msgid ""
+"\tadd\tesp, byte 8\n"
+"\tmov\t[fd.in], eax\n"
+"\tjmp\t.arg\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2463
+#, no-wrap
+msgid ""
+".p:\n"
+"\tcmp\tal, 'p'\n"
+"\tjne\t.t\n"
+"\tor\tah, ah\n"
+"\tjne\tnear usage\n"
+"\tor\tedx, 1 << 31\n"
+"\tjmp\t.arg\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2471
+#, no-wrap
+msgid ""
+".t:\n"
+"\tcmp\tal, 't'\t\t; redefine output delimiter\n"
+"\tjne\t.c\n"
+"\tor\tah, ah\n"
+"\tje\tnear usage\n"
+"\tmov\tdl, ah\n"
+"\tjmp\t.arg\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2479
+#, no-wrap
+msgid ""
+".c:\n"
+"\tcmp\tal, 'c'\n"
+"\tjne\tnear usage\n"
+"\tor\tah, ah\n"
+"\tje\tnear usage\n"
+"\tmov\tdh, ah\n"
+"\tjmp\t.arg\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2486
+#, no-wrap
+msgid ""
+"align 4\n"
+".init:\n"
+"\tsub\teax, eax\n"
+"\tsub\tebx, ebx\n"
+"\tsub\tecx, ecx\n"
+"\tmov\tedi, obuffer\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2490
+#, no-wrap
+msgid ""
+"\t; See if we are to preserve the first line\n"
+"\tor\tedx, edx\n"
+"\tjs\t.loop\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2496
+#, no-wrap
+msgid ""
+".firstline:\n"
+"\t; get rid of the first line\n"
+"\tcall\tgetchar\n"
+"\tcmp\tal, 0Ah\n"
+"\tjne\t.firstline\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2504
+#, no-wrap
+msgid ""
+"\t; is it a comma (or whatever the user asked for)?\n"
+"\tcmp\tal, dh\n"
+"\tjne\t.quote\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2507
+#, no-wrap
+msgid ""
+"\t; Replace the comma with a tab (or whatever the user wants)\n"
+"\tmov\tal, dl\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2515
+#, no-wrap
+msgid ""
+".quote:\n"
+"\tcmp\tal, '\"'\n"
+"\tjne\t.put\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2522
+#, no-wrap
+msgid ""
+"\t; Print everything until you get another quote or EOL. If it\n"
+"\t; is a quote, skip it. If it is EOL, print it.\n"
+".qloop:\n"
+"\tcall\tgetchar\n"
+"\tcmp\tal, '\"'\n"
+"\tje\t.loop\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2525
+#, no-wrap
+msgid ""
+"\tcmp\tal, 0Ah\n"
+"\tje\t.put\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2528
+#, no-wrap
+msgid ""
+"\tcall\tputchar\n"
+"\tjmp\tshort .qloop\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2544
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3859
+#, no-wrap
+msgid ""
+"read:\n"
+"\tjecxz\t.read\n"
+"\tcall\twrite\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2557
+#, no-wrap
+msgid ""
+".read:\n"
+"\tpush\tdword BUFSIZE\n"
+"\tmov\tesi, ibuffer\n"
+"\tpush\tesi\n"
+"\tpush\tdword [fd.in]\n"
+"\tsys.read\n"
+"\tadd\tesp, byte 12\n"
+"\tmov\tebx, eax\n"
+"\tor\teax, eax\n"
+"\tje\t.done\n"
+"\tsub\teax, eax\n"
+"\tret\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2594
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3900
+#, no-wrap
+msgid ""
+"align 4\n"
+"write:\n"
+"\tjecxz\t.ret\t; nothing to write\n"
+"\tsub\tedi, ecx\t; start of buffer\n"
+"\tpush\tecx\n"
+"\tpush\tedi\n"
+"\tpush\tdword [fd.out]\n"
+"\tsys.write\n"
+"\tadd\tesp, byte 12\n"
+"\tsub\teax, eax\n"
+"\tsub\tecx, ecx\t; buffer is empty now\n"
+".ret:\n"
+"\tret\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2599
+msgid ""
+"Much of it is taken from [.filename]#hex.asm# above. But there is one "
+"important difference: I no longer call `write` whenever I am outputting a "
+"line feed. Yet, the code can be used interactively."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2603
+msgid ""
+"I have found a better solution for the interactive problem since I first "
+"started writing this chapter. I wanted to make sure each line is printed "
+"out separately only when needed. After all, there is no need to flush out "
+"every line when used non-interactively."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2607
+msgid ""
+"The new solution I use now is to call `write` every time I find the input "
+"buffer empty. That way, when running in the interactive mode, the program "
+"reads one line from the user's keyboard, processes it, and sees its input "
+"buffer is empty. It flushes its output and reads the next line."
+msgstr ""
+
+#. type: Title ====
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2609
+#, no-wrap
+msgid "The Dark Side of Buffering"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2613
+msgid ""
+"This change prevents a mysterious lockup in a very specific case. I refer "
+"to it as the _dark side of buffering_, mostly because it presents a danger "
+"that is not quite obvious."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2617
+msgid ""
+"It is unlikely to happen with a program like the csv above, so let us "
+"consider yet another filter: In this case we expect our input to be raw data "
+"representing color values, such as the _red_, _green_, and _blue_ "
+"intensities of a pixel. Our output will be the negative of our input."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2620
+msgid ""
+"Such a filter would be very simple to write. Most of it would look just "
+"like all the other filters we have written so far, so I am only going to "
+"show you its inner loop:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2628
+#, no-wrap
+msgid ""
+".loop:\n"
+"\tcall\tgetchar\n"
+"\tnot\tal\t\t; Create a negative\n"
+"\tcall\tputchar\n"
+"\tjmp\tshort .loop\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2631
+msgid ""
+"Because this filter works with raw data, it is unlikely to be used "
+"interactively."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2634
+msgid ""
+"But it could be called by image manipulation software. And, unless it calls "
+"`write` before each call to `read`, chances are it will lock up."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2636
+msgid "Here is what might happen:"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2639
+msgid "The image editor will load our filter using the C function `popen()`."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2640
+msgid "It will read the first row of pixels from a bitmap or pixmap."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2641
+msgid ""
+"It will write the first row of pixels to the _pipe_ leading to the `fd.in` "
+"of our filter."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2642
+msgid ""
+"Our filter will read each pixel from its input, turn it to a negative, and "
+"write it to its output buffer."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2643
+msgid "Our filter will call `getchar` to fetch the next pixel."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2644
+msgid "`getchar` will find an empty input buffer, so it will call `read`."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2645
+msgid "`read` will call the `SYS_read` system call."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2646
+msgid ""
+"The _kernel_ will suspend our filter until the image editor sends more data "
+"to the pipe."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2647
+msgid ""
+"The image editor will read from the other pipe, connected to the `fd.out` of "
+"our filter so it can set the first row of the output image _before_ it sends "
+"us the second row of the input."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2648
+msgid ""
+"The _kernel_ suspends the image editor until it receives some output from "
+"our filter, so it can pass it on to the image editor."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2652
+msgid ""
+"At this point our filter waits for the image editor to send it more data to "
+"process, while the image editor is waiting for our filter to send it the "
+"result of the processing of the first row. But the result sits in our "
+"output buffer."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2655
+msgid ""
+"The filter and the image editor will continue waiting for each other forever "
+"(or, at least, until they are killed). Our software has just entered a "
+"crossref:secure[secure-race-conditions,race condition]."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2657
+msgid ""
+"This problem does not exist if our filter flushes its output buffer _before_ "
+"asking the _kernel_ for more input data."
+msgstr ""
+
+#. type: Title ==
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2659
+#, no-wrap
+msgid "Using the FPU"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2662
+msgid ""
+"Strangely enough, most of assembly language literature does not even mention "
+"the existence of the FPU, or _floating point unit_, let alone discuss "
+"programming it."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2664
+msgid ""
+"Yet, never does assembly language shine more than when we create highly "
+"optimized FPU code by doing things that can be done _only_ in assembly "
+"language."
+msgstr ""
+
+#. type: Title ===
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2666
+#, no-wrap
+msgid "Organization of the FPU"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2670
+msgid ""
+"The FPU consists of 8 80-bit floating-point registers. These are organized "
+"in a stack fashion-you can `push` a value on TOS (_top of stack_) and you "
+"can `pop` it."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2672
+msgid ""
+"That said, the assembly language op codes are not `push` and `pop` because "
+"those are already taken."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2675
+msgid ""
+"You can `push` a value on TOS by using `fld`, `fild`, and `fbld`. Several "
+"other op codes let you `push` many common _constants_-such as _pi_-on the "
+"TOS."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2678
+msgid ""
+"Similarly, you can `pop` a value by using `fst`, `fstp`, `fist`, `fistp`, "
+"and `fbstp`. Actually, only the op codes that end with a _p_ will literally "
+"`pop` the value, the rest will `store` it somewhere else without removing it "
+"from the TOS."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2680
+msgid ""
+"We can transfer the data between the TOS and the computer memory either as a "
+"32-bit, 64-bit, or 80-bit _real_, a 16-bit, 32-bit, or 64-bit _integer_, or "
+"an 80-bit _packed decimal_."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2683
+msgid ""
+"The 80-bit _packed decimal_ is a special case of _binary coded decimal_ "
+"which is very convenient when converting between the ASCII representation of "
+"data and the internal data of the FPU. It allows us to use 18 significant "
+"digits."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2685
+msgid ""
+"No matter how we represent data in the memory, the FPU always stores it in "
+"the 80-bit _real_ format in its registers."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2687
+msgid ""
+"Its internal precision is at least 19 decimal digits, so even if we choose "
+"to display results as ASCII in the full 18-digit precision, we are still "
+"showing correct results."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2689
+msgid ""
+"We can perform mathematical operations on the TOS: We can calculate its "
+"_sine_, we can _scale_ it (i.e., we can multiply or divide it by a power of "
+"2), we can calculate its base-2 _logarithm_, and many other things."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2691
+msgid ""
+"We can also _multiply_ or _divide_ it by, _add_ it to, or _subtract_ it "
+"from, any of the FPU registers (including itself)."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2694
+msgid ""
+"The official Intel op code for the TOS is `st`, and for the _registers_ "
+"`st(0)`-`st(7)`. `st` and `st(0)`, then, refer to the same register."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2697
+msgid ""
+"For whatever reasons, the original author of nasm has decided to use "
+"different op codes, namely `st0`-`st7`. In other words, there are no "
+"parentheses, and the TOS is always `st0`, never just `st`."
+msgstr ""
+
+#. type: Title ====
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2699
+#, no-wrap
+msgid "The Packed Decimal Format"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2703
+msgid ""
+"The _packed decimal_ format uses 10 bytes (80 bits) of memory to represent "
+"18 digits. The number represented there is always an _integer_."
+msgstr ""
+
+#. type: delimited block = 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2707
+msgid ""
+"You can use it to get decimal places by multiplying the TOS by a power of 10 "
+"first."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2711
+msgid ""
+"The highest bit of the highest byte (byte 9) is the _sign bit_: If it is "
+"set, the number is _negative_, otherwise, it is _positive_. The rest of the "
+"bits of this byte are unused/ignored."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2713
+msgid ""
+"The remaining 9 bytes store the 18 digits of the number: 2 digits per byte."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2715
+msgid ""
+"The _more significant digit_ is stored in the high _nibble_ (4 bits), the "
+"_less significant digit_ in the low _nibble_."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2717
+msgid ""
+"That said, you might think that `-1234567` would be stored in the memory "
+"like this (using hexadecimal notation):"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2721
+#, no-wrap
+msgid "80 00 00 00 00 00 01 23 45 67\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2724
+msgid ""
+"Alas it is not! As with everything else of Intel make, even the _packed "
+"decimal_ is _little-endian_."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2726
+msgid "That means our `-1234567` is stored like this:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2730
+#, no-wrap
+msgid "67 45 23 01 00 00 00 00 00 80\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2733
+msgid "Remember that, or you will be pulling your hair out in desperation!"
+msgstr ""
+
+#. type: delimited block = 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2739
+msgid ""
+"The book to read-if you can find it-is Richard Startz' http://www.amazon.com/"
+"exec/obidos/ASIN/013246604X/whizkidtechnomag[8087/80287/80387 for the IBM PC "
+"& Compatibles]. Though it does seem to take the fact about the little-"
+"endian storage of the _packed decimal_ for granted. I kid you not about the "
+"desperation of trying to figure out what was wrong with the filter I show "
+"below _before_ it occurred to me I should try the little-endian order even "
+"for this type of data."
+msgstr ""
+
+#. type: Title ===
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2742
+#, no-wrap
+msgid "Excursion to Pinhole Photography"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2745
+msgid ""
+"To write meaningful software, we must not only understand our programming "
+"tools, but also the field we are creating software for."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2747
+msgid ""
+"Our next filter will help us whenever we want to build a _pinhole camera_, "
+"so, we need some background in _pinhole photography_ before we can continue."
+msgstr ""
+
+#. type: Title ====
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2749
+#, no-wrap
+msgid "The Camera"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2752
+msgid ""
+"The easiest way to describe any camera ever built is as some empty space "
+"enclosed in some lightproof material, with a small hole in the enclosure."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2757
+msgid ""
+"The enclosure is usually sturdy (e.g., a box), though sometimes it is "
+"flexible (the bellows). It is quite dark inside the camera. However, the "
+"hole lets light rays in through a single point (though in some cases there "
+"may be several). These light rays form an image, a representation of "
+"whatever is outside the camera, in front of the hole."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2759
+msgid ""
+"If some light sensitive material (such as film) is placed inside the camera, "
+"it can capture the image."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2761
+msgid ""
+"The hole often contains a _lens_, or a lens assembly, often called the "
+"_objective_."
+msgstr ""
+
+#. type: Title ====
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2763
+#, no-wrap
+msgid "The Pinhole"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2767
+msgid ""
+"But, strictly speaking, the lens is not necessary: The original cameras did "
+"not use a lens but a _pinhole_. Even today, _pinholes_ are used, both as a "
+"tool to study how cameras work, and to achieve a special kind of image."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2771
+msgid ""
+"The image produced by the _pinhole_ is all equally sharp. Or _blurred_. "
+"There is an ideal size for a pinhole: If it is either larger or smaller, the "
+"image loses its sharpness."
+msgstr ""
+
+#. type: Title ====
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2773
+#, no-wrap
+msgid "Focal Length"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2776
+msgid ""
+"This ideal pinhole diameter is a function of the square root of _focal "
+"length_, which is the distance of the pinhole from the film."
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2780
+#, no-wrap
+msgid "D = PC * sqrt(FL)\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2786
+msgid ""
+"In here, `D` is the ideal diameter of the pinhole, `FL` is the focal length, "
+"and `PC` is a pinhole constant. According to Jay Bender, its value is "
+"`0.04`, while Kenneth Connors has determined it to be `0.037`. Others have "
+"proposed other values. Plus, this value is for the daylight only: Other "
+"types of light will require a different constant, whose value can only be "
+"determined by experimentation."
+msgstr ""
+
+#. type: Title ====
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2788
+#, no-wrap
+msgid "The F-Number"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2792
+msgid ""
+"The f-number is a very useful measure of how much light reaches the film. A "
+"light meter can determine that, for example, to expose a film of specific "
+"sensitivity with f5.6 mkay require the exposure to last 1/1000 sec."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2795
+msgid ""
+"It does not matter whether it is a 35-mm camera, or a 6x9cm camera, etc. As "
+"long as we know the f-number, we can determine the proper exposure."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2797
+msgid "The f-number is easy to calculate:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2801
+#, no-wrap
+msgid "F = FL / D\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2806
+msgid ""
+"In other words, the f-number equals the focal length divided by the diameter "
+"of the pinhole. It also means a higher f-number either implies a smaller "
+"pinhole or a larger focal distance, or both. That, in turn, implies, the "
+"higher the f-number, the longer the exposure has to be."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2809
+msgid ""
+"Furthermore, while pinhole diameter and focal distance are one-dimensional "
+"measurements, both, the film and the pinhole, are two-dimensional. That "
+"means that if you have measured the exposure at f-number `A` as `t`, then "
+"the exposure at f-number `B` is:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2813
+#, no-wrap
+msgid "t * (B / A)²\n"
+msgstr ""
+
+#. type: Title ====
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2816
+#, no-wrap
+msgid "Normalized F-Number"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2819
+msgid ""
+"While many modern cameras can change the diameter of their pinhole, and thus "
+"their f-number, quite smoothly and gradually, such was not always the case."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2821
+msgid ""
+"To allow for different f-numbers, cameras typically contained a metal plate "
+"with several holes of different sizes drilled to them."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2824
+msgid ""
+"Their sizes were chosen according to the above formula in such a way that "
+"the resultant f-number was one of standard f-numbers used on all cameras "
+"everywhere. For example, a very old Kodak Duaflex IV camera in my "
+"possession has three such holes for f-numbers 8, 11, and 16."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2827
+msgid ""
+"A more recently made camera may offer f-numbers of 2.8, 4, 5.6, 8, 11, 16, "
+"22, and 32 (as well as others). These numbers were not chosen arbitrarily: "
+"They all are powers of the square root of 2, though they may be rounded "
+"somewha."
+msgstr ""
+
+#. type: Title ====
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2829
+#, no-wrap
+msgid "The F-Stop"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2833
+msgid ""
+"A typical camera is designed in such a way that setting any of the "
+"normalized f-numbers changes the feel of the dial. It will naturally _stop_ "
+"in that position. Because of that, these positions of the dial are called f-"
+"stops."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2837
+msgid ""
+"Since the f-numbers at each stop are powers of the square root of 2, moving "
+"the dial by 1 stop will double the amount of light required for proper "
+"exposure. Moving it by 2 stops will quadruple the required exposure. "
+"Moving the dial by 3 stops will require the increase in exposure 8 times, "
+"etc."
+msgstr ""
+
+#. type: Title ===
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2839
+#, no-wrap
+msgid "Designing the Pinhole Software"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2842
+msgid ""
+"We are now ready to decide what exactly we want our pinhole software to do."
+msgstr ""
+
+#. type: Title ====
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2844
+#, no-wrap
+msgid "Processing Program Input"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2848
+msgid ""
+"Since its main purpose is to help us design a working pinhole camera, we "
+"will use the _focal length_ as the input to the program. This is something "
+"we can determine without software: Proper focal length is determined by the "
+"size of the film and by the need to shoot \"regular\" pictures, wide angle "
+"pictures, or telephoto pictures."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2850
+msgid ""
+"Most of the programs we have written so far worked with individual "
+"characters, or bytes, as their input: The hex program converted individual "
+"bytes into a hexadecimal number, the csv program either let a character "
+"through, or deleted it, or changed it to a different character, etc."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2852
+msgid ""
+"One program, ftuc used the state machine to consider at most two input bytes "
+"at a time."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2854
+msgid ""
+"But our pinhole program cannot just work with individual characters, it has "
+"to deal with larger syntactic units."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2856
+msgid ""
+"For example, if we want the program to calculate the pinhole diameter (and "
+"other values we will discuss later) at the focal lengths of `100 mm`, `150 "
+"mm`, and `210 mm`, we may want to enter something like this:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2860
+#, no-wrap
+msgid " 100, 150, 210\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2865
+msgid ""
+"Our program needs to consider more than a single byte of input at a time. "
+"When it sees the first `1`, it must understand it is seeing the first digit "
+"of a decimal number. When it sees the `0` and the other `0`, it must know "
+"it is seeing more digits of the same number."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2870
+msgid ""
+"When it encounters the first comma, it must know it is no longer receiving "
+"the digits of the first number. It must be able to convert the digits of "
+"the first number into the value of `100`. And the digits of the second "
+"number into the value of `150`. And, of course, the digits of the third "
+"number into the numeric value of `210`."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2872
+msgid ""
+"We need to decide what delimiters to accept: Do the input numbers have to be "
+"separated by a comma? If so, how do we treat two numbers separated by "
+"something else?"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2877
+msgid ""
+"Personally, I like to keep it simple. Something either is a number, so I "
+"process it. Or it is not a number, so I discard it. I do not like the "
+"computer complaining about me typing in an extra character when it is "
+"_obvious_ that it is an extra character. Duh!"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2879
+msgid ""
+"Plus, it allows me to break up the monotony of computing and type in a query "
+"instead of just a number:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2884
+#, no-wrap
+msgid ""
+"What is the best pinhole diameter for the\n"
+"\t focal length of 150?\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2887
+msgid "There is no reason for the computer to spit out a number of complaints:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2894
+#, no-wrap
+msgid ""
+"Syntax error: What\n"
+"Syntax error: is\n"
+"Syntax error: the\n"
+"Syntax error: best\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2897
+msgid "Et cetera, et cetera, et cetera."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2900
+msgid ""
+"Secondly, I like the `+#+` character to denote the start of a comment which "
+"extends to the end of the line. This does not take too much effort to code, "
+"and lets me treat input files for my software as executable scripts."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2902
+msgid ""
+"In our case, we also need to decide what units the input should come in: We "
+"choose _millimeters_ because that is how most photographers measure the "
+"focus length."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2904
+msgid ""
+"Finally, we need to decide whether to allow the use of the decimal point (in "
+"which case we must also consider the fact that much of the world uses a "
+"decimal _comma_)."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2908
+msgid ""
+"In our case allowing for the decimal point/comma would offer a false sense "
+"of precision: There is little if any noticeable difference between the focus "
+"lengths of `50` and `51`, so allowing the user to input something like "
+"`50.5` is not a good idea. This is my opinion, mind you, but I am the one "
+"writing this program. You can make other choices in yours, of course."
+msgstr ""
+
+#. type: Title ====
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2910
+#, no-wrap
+msgid "Offering Options"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2915
+msgid ""
+"The most important thing we need to know when building a pinhole camera is "
+"the diameter of the pinhole. Since we want to shoot sharp images, we will "
+"use the above formula to calculate the pinhole diameter from focal length. "
+"As experts are offering several different values for the `PC` constant, we "
+"will need to have the choice."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2917
+msgid ""
+"It is traditional in UNIX(R) programming to have two main ways of choosing "
+"program parameters, plus to have a default for the time the user does not "
+"make a choice."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2919
+msgid "Why have two ways of choosing?"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2921
+msgid ""
+"One is to allow a (relatively) _permanent_ choice that applies automatically "
+"each time the software is run without us having to tell it over and over "
+"what we want it to do."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2926
+msgid ""
+"The permanent choices may be stored in a configuration file, typically found "
+"in the user's home directory. The file usually has the same name as the "
+"application but is started with a dot. Often _\"rc\"_ is added to the file "
+"name. So, ours could be [.filename]#~/.pinhole# or [.filename]#~/."
+"pinholerc#. (The [.filename]#~/# means current user's home directory.)"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2931
+msgid ""
+"The configuration file is used mostly by programs that have many "
+"configurable parameters. Those that have only one (or a few) often use a "
+"different method: They expect to find the parameter in an _environment "
+"variable_. In our case, we might look at an environment variable named "
+"`PINHOLE`."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2934
+msgid ""
+"Usually, a program uses one or the other of the above methods. Otherwise, "
+"if a configuration file said one thing, but an environment variable another, "
+"the program might get confused (or just too complicated)."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2936
+msgid ""
+"Because we only need to choose _one_ such parameter, we will go with the "
+"second method and search the environment for a variable named `PINHOLE`."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2939
+msgid ""
+"The other way allows us to make _ad hoc_ decisions: _\"Though I usually want "
+"you to use 0.039, this time I want 0.03872.\"_ In other words, it allows us "
+"to _override_ the permanent choice."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2941
+msgid "This type of choice is usually done with command line parameters."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2949
+msgid ""
+"Finally, a program _always_ needs a _default_. The user may not make any "
+"choices. Perhaps he does not know what to choose. Perhaps he is \"just "
+"browsing.\" Preferably, the default will be the value most users would "
+"choose anyway. That way they do not need to choose. Or, rather, they can "
+"choose the default without an additional effort."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2951
+msgid ""
+"Given this system, the program may find conflicting options, and handle them "
+"this way:"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2954
+msgid ""
+"If it finds an _ad hoc_ choice (e.g., command line parameter), it should "
+"accept that choice. It must ignore any permanent choice and any default."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2955
+msgid ""
+"_Otherwise_, if it finds a permanent option (e.g., an environment variable), "
+"it should accept it, and ignore the default."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2956
+msgid "_Otherwise_, it should use the default."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2958
+msgid "We also need to decide what _format_ our `PC` option should have."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2960
+msgid ""
+"At first site, it seems obvious to use the `PINHOLE=0.04` format for the "
+"environment variable, and `-p0.04` for the command line."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2964
+msgid ""
+"Allowing that is actually a security risk. The `PC` constant is a very small "
+"number. Naturally, we will test our software using various small values of "
+"`PC`. But what will happen if someone runs the program choosing a huge "
+"value?"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2966
+msgid ""
+"It may crash the program because we have not designed it to handle huge "
+"numbers."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2969
+msgid ""
+"Or, we may spend more time on the program so it can handle huge numbers. We "
+"might do that if we were writing commercial software for computer illiterate "
+"audience."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2971
+msgid "Or, we might say, _\"Tough! The user should know better.\"\"_"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2974
+msgid ""
+"Or, we just may make it impossible for the user to enter a huge number. "
+"This is the approach we will take: We will use an _implied 0._ prefix."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2977
+msgid ""
+"In other words, if the user wants `0.04`, we will expect him to type `-p04`, "
+"or set `PINHOLE=04` in his environment. So, if he says `-p9999999`, we will "
+"interpret it as ``0.9999999``-still ridiculous but at least safer."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2980
+msgid ""
+"Secondly, many users will just want to go with either Bender's constant or "
+"Connors' constant. To make it easier on them, we will interpret `-b` as "
+"identical to `-p04`, and `-c` as identical to `-p037`."
+msgstr ""
+
+#. type: Title ====
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2982
+#, no-wrap
+msgid "The Output"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2985
+msgid ""
+"We need to decide what we want our software to send to the output, and in "
+"what format."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2987
+msgid ""
+"Since our input allows for an unspecified number of focal length entries, it "
+"makes sense to use a traditional database-style output of showing the result "
+"of the calculation for each focal length on a separate line, while "
+"separating all values on one line by a `tab` character."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2990
+msgid ""
+"Optionally, we should also allow the user to specify the use of the CSV "
+"format we have studied earlier. In this case, we will print out a line of "
+"comma-separated names describing each field of every line, then show our "
+"results as before, but substituting a `comma` for the `tab`."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2995
+msgid ""
+"We need a command line option for the CSV format. We cannot use `-c` "
+"because that already means _use Connors' constant_. For some strange "
+"reason, many web sites refer to CSV files as _\"Excel spreadsheet\"_ (though "
+"the CSV format predates Excel). We will, therefore, use the `-e` switch to "
+"inform our software we want the output in the CSV format."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:2999
+msgid ""
+"We will start each line of the output with the focal length. This may sound "
+"repetitious at first, especially in the interactive mode: The user types in "
+"the focal length, and we are repeating it."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3003
+msgid ""
+"But the user can type several focal lengths on one line. The input can also "
+"come in from a file or from the output of another program. In that case the "
+"user does not see the input at all."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3005
+msgid ""
+"By the same token, the output can go to a file which we will want to examine "
+"later, or it could go to the printer, or become the input of another program."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3007
+msgid ""
+"So, it makes perfect sense to start each line with the focal length as "
+"entered by the user."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3010
+msgid ""
+"No, wait! Not as entered by the user. What if the user types in something "
+"like this:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3014
+#, no-wrap
+msgid " 00000000150\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3017
+msgid "Clearly, we need to strip those leading zeros."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3019
+msgid ""
+"So, we might consider reading the user input as is, converting it to binary "
+"inside the FPU, and printing it out from there."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3021
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3206
+msgid "But..."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3023
+msgid "What if the user types something like this:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3027
+#, no-wrap
+msgid " 17459765723452353453534535353530530534563507309676764423\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3032
+msgid ""
+"Ha! The packed decimal FPU format lets us input 18-digit numbers. But the "
+"user has entered more than 18 digits. How do we handle that?"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3034
+msgid ""
+"Well, we _could_ modify our code to read the first 18 digits, enter it to "
+"the FPU, then read more, multiply what we already have on the TOS by 10 "
+"raised to the number of additional digits, then `add` to it."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3038
+msgid ""
+"Yes, we could do that. But in _this_ program it would be ridiculous (in a "
+"different one it may be just the thing to do): Even the circumference of the "
+"Earth expressed in millimeters only takes 11 digits. Clearly, we cannot "
+"build a camera that large (not yet, anyway)."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3040
+msgid ""
+"So, if the user enters such a huge number, he is either bored, or testing "
+"us, or trying to break into the system, or playing games-doing anything but "
+"designing a pinhole camera."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3042
+msgid "What will we do?"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3044
+msgid "We will slap him in the face, in a manner of speaking:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3048
+#, no-wrap
+msgid "17459765723452353453534535353530530534563507309676764423\t???\t???\t???\t???\t???\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3052
+msgid ""
+"To achieve that, we will simply ignore any leading zeros. Once we find a "
+"non-zero digit, we will initialize a counter to `0` and start taking three "
+"steps:"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3055
+msgid "Send the digit to the output."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3056
+msgid ""
+"Append the digit to a buffer we will use later to produce the packed decimal "
+"we can send to the FPU."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3057
+msgid "Increase the counter."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3059
+msgid ""
+"Now, while we are taking these three steps, we also need to watch out for "
+"one of two conditions:"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3061
+msgid ""
+"If the counter grows above 18, we stop appending to the buffer. We continue "
+"reading the digits and sending them to the output."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3062
+msgid ""
+"If, or rather _when_, the next input character is not a digit, we are done "
+"inputting for now."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3065
+msgid ""
+"Incidentally, we can simply discard the non-digit, unless it is a `+#+`, "
+"which we must return to the input stream. It starts a comment, so we must "
+"see it after we are done producing output and start looking for more input."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3067
+msgid ""
+"That still leaves one possibility uncovered: If all the user enters is a "
+"zero (or several zeros), we will never find a non-zero to display."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3070
+msgid ""
+"We can determine this has happened whenever our counter stays at `0`. In "
+"that case we need to send `0` to the output, and perform another \"slap in "
+"the face\":"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3074
+#, no-wrap
+msgid "0\t???\t???\t???\t???\t???\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3077
+msgid ""
+"Once we have displayed the focal length and determined it is valid (greater "
+"than `0` but not exceeding 18 digits), we can calculate the pinhole diameter."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3080
+msgid ""
+"It is not by coincidence that _pinhole_ contains the word _pin_. Indeed, "
+"many a pinhole literally is a _pin hole_, a hole carefully punched with the "
+"tip of a pin."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3083
+msgid ""
+"That is because a typical pinhole is very small. Our formula gets the result "
+"in millimeters. We will multiply it by `1000`, so we can output the result "
+"in _microns_."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3085
+msgid "At this point we have yet another trap to face: _Too much precision._"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3089
+msgid ""
+"Yes, the FPU was designed for high precision mathematics. But we are not "
+"dealing with high precision mathematics. We are dealing with physics "
+"(optics, specifically)."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3093
+msgid ""
+"Suppose we want to convert a truck into a pinhole camera (we would not be "
+"the first ones to do that!). Suppose its box is `12` meters long, so we "
+"have the focal length of `12000`. Well, using Bender's constant, it gives "
+"us square root of `12000` multiplied by `0.04`, which is `4.381780460` "
+"millimeters, or `4381.780460` microns."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3098
+msgid ""
+"Put either way, the result is absurdly precise. Our truck is not _exactly_ "
+"`12000` millimeters long. We did not measure its length with such a "
+"precision, so stating we need a pinhole with the diameter of `4.381780460` "
+"millimeters is, well, deceiving. `4.4` millimeters would do just fine."
+msgstr ""
+
+#. type: delimited block = 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3103
+msgid ""
+"I \"only\" used ten digits in the above example. Imagine the absurdity of "
+"going for all 18!"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3109
+msgid ""
+"We need to limit the number of significant digits of our result. One way of "
+"doing it is by using an integer representing microns. So, our truck would "
+"need a pinhole with the diameter of `4382` microns. Looking at that number, "
+"we still decide that `4400` microns, or `4.4` millimeters is close enough."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3112
+msgid ""
+"Additionally, we can decide that no matter how big a result we get, we only "
+"want to display four significant digits (or any other number of them, of "
+"course). Alas, the FPU does not offer rounding to a specific number of "
+"digits (after all, it does not view the numbers as decimal but as binary)."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3114
+msgid ""
+"We, therefore, must devise an algorithm to reduce the number of significant "
+"digits."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3116
+msgid ""
+"Here is mine (I think it is awkward-if you know a better one, _please_, let "
+"me know):"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3119
+msgid "Initialize a counter to `0`."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3120
+msgid ""
+"While the number is greater than or equal to `10000`, divide it by `10` and "
+"increase the counter."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3121
+msgid "Output the result."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3122
+msgid ""
+"While the counter is greater than `0`, output `0` and decrease the counter."
+msgstr ""
+
+#. type: delimited block = 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3127
+msgid ""
+"The `10000` is only good if you want _four_ significant digits. For any "
+"other number of significant digits, replace `10000` with `10` raised to the "
+"number of significant digits."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3130
+msgid ""
+"We will, then, output the pinhole diameter in microns, rounded off to four "
+"significant digits."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3133
+msgid ""
+"At this point, we know the _focal length_ and the _pinhole diameter_. That "
+"means we have enough information to also calculate the _f-number_."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3137
+msgid ""
+"We will display the f-number, rounded to four significant digits. Chances "
+"are the f-number will tell us very little. To make it more meaningful, we "
+"can find the nearest _normalized f-number_, i.e., the nearest power of the "
+"square root of 2."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3143
+msgid ""
+"We do that by multiplying the actual f-number by itself, which, of course, "
+"will give us its `square`. We will then calculate its base-2 logarithm, "
+"which is much easier to do than calculating the base-square-root-of-2 "
+"logarithm! We will round the result to the nearest integer. Next, we will "
+"raise 2 to the result. Actually, the FPU gives us a good shortcut to do "
+"that: We can use the `fscale` op code to \"scale\" 1, which is analogous to "
+"``shift``ing an integer left. Finally, we calculate the square root of it "
+"all, and we have the nearest normalized f-number."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3146
+msgid ""
+"If all that sounds overwhelming-or too much work, perhaps-it may become much "
+"clearer if you see the code. It takes 9 op codes altogether:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3158
+#, no-wrap
+msgid ""
+"fmul\tst0, st0\n"
+"\tfld1\n"
+"\tfld\tst1\n"
+"\tfyl2x\n"
+"\tfrndint\n"
+"\tfld1\n"
+"\tfscale\n"
+"\tfsqrt\n"
+"\tfstp\tst1\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3162
+msgid ""
+"The first line, `fmul st0, st0`, squares the contents of the TOS (top of the "
+"stack, same as `st`, called `st0` by nasm). The `fld1` pushes `1` on the "
+"TOS."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3166
+msgid ""
+"The next line, `fld st1`, pushes the square back to the TOS. At this point "
+"the square is both in `st` and `st(2)` (it will become clear why we leave a "
+"second copy on the stack in a moment). `st(1)` contains `1`."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3169
+msgid ""
+"Next, `fyl2x` calculates base-2 logarithm of `st` multiplied by `st(1)`. "
+"That is why we placed `1` on `st(1)` before."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3171
+msgid ""
+"At this point, `st` contains the logarithm we have just calculated, `st(1)` "
+"contains the square of the actual f-number we saved for later."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3175
+msgid ""
+"`frndint` rounds the TOS to the nearest integer. `fld1` pushes a `1`. "
+"`fscale` shifts the `1` we have on the TOS by the value in `st(1)`, "
+"effectively raising 2 to `st(1)`."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3177
+msgid ""
+"Finally, `fsqrt` calculates the square root of the result, i.e., the nearest "
+"normalized f-number."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3180
+msgid ""
+"We now have the nearest normalized f-number on the TOS, the base-2 logarithm "
+"rounded to the nearest integer in `st(1)`, and the square of the actual f-"
+"number in `st(2)`. We are saving the value in `st(2)` for later."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3186
+msgid ""
+"But we do not need the contents of `st(1)` anymore. The last line, `fstp "
+"st1`, places the contents of `st` to `st(1)`, and pops. As a result, what "
+"was `st(1)` is now `st`, what was `st(2)` is now `st(1)`, etc. The new `st` "
+"contains the normalized f-number. The new `st(1)` contains the square of "
+"the actual f-number we have stored there for posterity."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3189
+msgid ""
+"At this point, we are ready to output the normalized f-number. Because it "
+"is normalized, we will not round it off to four significant digits, but will "
+"send it out in its full precision."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3192
+msgid ""
+"The normalized f-number is useful as long as it is reasonably small and can "
+"be found on our light meter. Otherwise we need a different method of "
+"determining proper exposure."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3194
+msgid ""
+"Earlier we have figured out the formula of calculating proper exposure at an "
+"arbitrary f-number from that measured at a different f-number."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3197
+msgid ""
+"Every light meter I have ever seen can determine proper exposure at f5.6. "
+"We will, therefore, calculate an _\"f5.6 multiplier,\"_ i.e., by how much we "
+"need to multiply the exposure measured at f5.6 to determine the proper "
+"exposure for our pinhole camera."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3199
+msgid ""
+"From the above formula we know this factor can be calculated by dividing our "
+"f-number (the actual one, not the normalized one) by `5.6`, and squaring the "
+"result."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3201
+msgid ""
+"Mathematically, dividing the square of our f-number by the square of `5.6` "
+"will give us the same result."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3204
+msgid ""
+"Computationally, we do not want to square two numbers when we can only "
+"square one. So, the first solution seems better at first."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3212
+msgid ""
+"`5.6` is a _constant_. We do not have to have our FPU waste precious "
+"cycles. We can just tell it to divide the square of the f-number by "
+"whatever `5.6²` equals to. Or we can divide the f-number by `5.6`, and then "
+"square the result. The two ways now seem equal."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3214
+msgid "But, they are not!"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3218
+msgid ""
+"Having studied the principles of photography above, we remember that the "
+"`5.6` is actually square root of 2 raised to the fifth power. An "
+"_irrational_ number. The square of this number is _exactly_ `32`."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3224
+msgid ""
+"Not only is `32` an integer, it is a power of 2. We do not need to divide "
+"the square of the f-number by `32`. We only need to use `fscale` to shift "
+"it right by five positions. In the FPU lingo it means we will `fscale` it "
+"with `st(1)` equal to `-5`. That is _much faster_ than a division."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3227
+msgid ""
+"So, now it has become clear why we have saved the square of the f-number on "
+"the top of the FPU stack. The calculation of the f5.6 multiplier is the "
+"easiest calculation of this entire program! We will output it rounded to "
+"four significant digits."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3230
+msgid ""
+"There is one more useful number we can calculate: The number of stops our f-"
+"number is from f5.6. This may help us if our f-number is just outside the "
+"range of our light meter, but we have a shutter which lets us set various "
+"speeds, and this shutter uses stops."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3233
+msgid ""
+"Say, our f-number is 5 stops from f5.6, and the light meter says we should "
+"use 1/1000 sec. Then we can set our shutter speed to 1/1000 first, then "
+"move the dial by 5 stops."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3238
+msgid ""
+"This calculation is quite easy as well. All we have to do is to calculate "
+"the base-2 logarithm of the f5.6 multiplier we had just calculated (though "
+"we need its value from before we rounded it off). We then output the result "
+"rounded to the nearest integer. We do not need to worry about having more "
+"than four significant digits in this one: The result is most likely to have "
+"only one or two digits anyway."
+msgstr ""
+
+#. type: Title ===
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3240
+#, no-wrap
+msgid "FPU Optimizations"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3243
+msgid ""
+"In assembly language we can optimize the FPU code in ways impossible in high "
+"languages, including C."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3247
+msgid ""
+"Whenever a C function needs to calculate a floating-point value, it loads "
+"all necessary variables and constants into FPU registers. It then does "
+"whatever calculation is required to get the correct result. Good C "
+"compilers can optimize that part of the code really well."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3251
+msgid ""
+"It \"returns\" the value by leaving the result on the TOS. However, before "
+"it returns, it cleans up. Any variables and constants it used in its "
+"calculation are now gone from the FPU."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3253
+msgid ""
+"It cannot do what we just did above: We calculated the square of the f-"
+"number and kept it on the stack for later use by another function."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3256
+msgid ""
+"We _knew_ we would need that value later on. We also knew we had enough "
+"room on the stack (which only has room for 8 numbers) to store it there."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3258
+msgid ""
+"A C compiler has no way of knowing that a value it has on the stack will be "
+"required again in the very near future."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3261
+msgid ""
+"Of course, the C programmer may know it. But the only recourse he has is to "
+"store the value in a memory variable."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3263
+msgid ""
+"That means, for one, the value will be changed from the 80-bit precision "
+"used internally by the FPU to a C _double_ (64 bits) or even _single_ (32 "
+"bits)."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3266
+msgid ""
+"That also means that the value must be moved from the TOS into the memory, "
+"and then back again. Alas, of all FPU operations, the ones that access the "
+"computer memory are the slowest."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3268
+msgid ""
+"So, whenever programming the FPU in assembly language, look for the ways of "
+"keeping intermediate results on the FPU stack."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3270
+msgid ""
+"We can take that idea even further! In our program we are using a _constant_ "
+"(the one we named `PC`)."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3273
+msgid ""
+"It does not matter how many pinhole diameters we are calculating: 1, 10, 20, "
+"1000, we are always using the same constant. Therefore, we can optimize our "
+"program by keeping the constant on the stack all the time."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3276
+msgid ""
+"Early on in our program, we are calculating the value of the above "
+"constant. We need to divide our input by `10` for every digit in the "
+"constant."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3279
+msgid ""
+"It is much faster to multiply than to divide. So, at the start of our "
+"program, we divide `10` into `1` to obtain `0.1`, which we then keep on the "
+"stack: Instead of dividing the input by `10` for every digit, we multiply it "
+"by `0.1`."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3283
+msgid ""
+"By the way, we do not input `0.1` directly, even though we could. We have a "
+"reason for that: While `0.1` can be expressed with just one decimal place, "
+"we do not know how many _binary_ places it takes. We, therefore, let the "
+"FPU calculate its binary value to its own high precision."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3288
+msgid ""
+"We are using other constants: We multiply the pinhole diameter by `1000` to "
+"convert it from millimeters to microns. We compare numbers to `10000` when "
+"we are rounding them off to four significant digits. So, we keep both, "
+"`1000` and `10000`, on the stack. And, of course, we reuse the `0.1` when "
+"rounding off numbers to four digits."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3294
+msgid ""
+"Last but not least, we keep `-5` on the stack. We need it to scale the "
+"square of the f-number, instead of dividing it by `32`. It is not by "
+"coincidence we load this constant last. That makes it the top of the stack "
+"when only the constants are on it. So, when the square of the f-number is "
+"being scaled, the `-5` is at `st(1)`, precisely where `fscale` expects it to "
+"be."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3297
+msgid ""
+"It is common to create certain constants from scratch instead of loading "
+"them from the memory. That is what we are doing with `-5`:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3306
+#, no-wrap
+msgid ""
+"\tfld1\t\t\t; TOS = 1\n"
+"\tfadd\tst0, st0\t; TOS = 2\n"
+"\tfadd\tst0, st0\t; TOS = 4\n"
+"\tfld1\t\t\t; TOS = 1\n"
+"\tfaddp\tst1, st0\t; TOS = 5\n"
+"\tfchs\t\t\t; TOS = -5\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3309
+msgid ""
+"We can generalize all these optimizations into one rule: _Keep repeat values "
+"on the stack!_"
+msgstr ""
+
+#. type: delimited block = 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3314
+msgid ""
+"_PostScript(R)_ is a stack-oriented programming language. There are many "
+"more books available about PostScript(R) than about the FPU assembly "
+"language: Mastering PostScript(R) will help you master the FPU."
+msgstr ""
+
+#. type: Title ===
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3317
+#, no-wrap
+msgid "pinhole-The Code"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3332
+#, no-wrap
+msgid ""
+";;;;;;; pinhole.asm ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n"
+";\n"
+"; Find various parameters of a pinhole camera construction and use\n"
+";\n"
+"; Started:\t 9-Jun-2001\n"
+"; Updated:\t10-Jun-2001\n"
+";\n"
+"; Copyright (c) 2001 G. Adam Stanislav\n"
+"; All rights reserved.\n"
+";\n"
+";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3367
+#, no-wrap
+msgid ""
+"section\t.data\n"
+"align 4\n"
+"ten\tdd\t10\n"
+"thousand\tdd\t1000\n"
+"tthou\tdd\t10000\n"
+"fd.in\tdd\tstdin\n"
+"fd.out\tdd\tstdout\n"
+"envar\tdb\t'PINHOLE='\t; Exactly 8 bytes, or 2 dwords long\n"
+"pinhole\tdb\t'04,', \t\t; Bender's constant (0.04)\n"
+"connors\tdb\t'037', 0Ah\t; Connors' constant\n"
+"usg\tdb\t'Usage: pinhole [-b] [-c] [-e] [-p <value>] [-o <outfile>] [-i <infile>]', 0Ah\n"
+"usglen\tequ\t$-usg\n"
+"iemsg\tdb\t\"pinhole: Can't open input file\", 0Ah\n"
+"iemlen\tequ\t$-iemsg\n"
+"oemsg\tdb\t\"pinhole: Can't create output file\", 0Ah\n"
+"oemlen\tequ\t$-oemsg\n"
+"pinmsg\tdb\t\"pinhole: The PINHOLE constant must not be 0\", 0Ah\n"
+"pinlen\tequ\t$-pinmsg\n"
+"toobig\tdb\t\"pinhole: The PINHOLE constant may not exceed 18 decimal places\", 0Ah\n"
+"biglen\tequ\t$-toobig\n"
+"huhmsg\tdb\t9, '???'\n"
+"separ\tdb\t9, '???'\n"
+"sep2\tdb\t9, '???'\n"
+"sep3\tdb\t9, '???'\n"
+"sep4\tdb\t9, '???', 0Ah\n"
+"huhlen\tequ\t$-huhmsg\n"
+"header\tdb\t'focal length in millimeters,pinhole diameter in microns,'\n"
+"\tdb\t'F-number,normalized F-number,F-5.6 multiplier,stops '\n"
+"\tdb\t'from F-5.6', 0Ah\n"
+"headlen\tequ\t$-header\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3373
+#, no-wrap
+msgid ""
+"section .bss\n"
+"ibuffer\tresb\tBUFSIZE\n"
+"obuffer\tresb\tBUFSIZE\n"
+"dbuffer\tresb\t20\t\t; decimal input buffer\n"
+"bbuffer\tresb\t10\t\t; BCD buffer\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3384
+#, no-wrap
+msgid ""
+"section\t.text\n"
+"align 4\n"
+"huh:\n"
+"\tcall\twrite\n"
+"\tpush\tdword huhlen\n"
+"\tpush\tdword huhmsg\n"
+"\tpush\tdword [fd.out]\n"
+"\tsys.write\n"
+"\tadd\tesp, byte 12\n"
+"\tret\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3393
+#, no-wrap
+msgid ""
+"align 4\n"
+"perr:\n"
+"\tpush\tdword pinlen\n"
+"\tpush\tdword pinmsg\n"
+"\tpush\tdword stderr\n"
+"\tsys.write\n"
+"\tpush\tdword 4\t\t; return failure\n"
+"\tsys.exit\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3402
+#, no-wrap
+msgid ""
+"align 4\n"
+"consttoobig:\n"
+"\tpush\tdword biglen\n"
+"\tpush\tdword toobig\n"
+"\tpush\tdword stderr\n"
+"\tsys.write\n"
+"\tpush\tdword 5\t\t; return failure\n"
+"\tsys.exit\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3411
+#, no-wrap
+msgid ""
+"align 4\n"
+"ierr:\n"
+"\tpush\tdword iemlen\n"
+"\tpush\tdword iemsg\n"
+"\tpush\tdword stderr\n"
+"\tsys.write\n"
+"\tpush\tdword 1\t\t; return failure\n"
+"\tsys.exit\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3435
+#, no-wrap
+msgid ""
+"align 4\n"
+"global\t_start\n"
+"_start:\n"
+"\tadd\tesp, byte 8\t; discard argc and argv[0]\n"
+"\tsub\tesi, esi\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3440
+#, no-wrap
+msgid ""
+".arg:\n"
+"\tpop\tecx\n"
+"\tor\tecx, ecx\n"
+"\tje\tnear .getenv\t\t; no more arguments\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3448
+#, no-wrap
+msgid ""
+"\tinc\tecx\n"
+"\tmov\tax, [ecx]\n"
+"\tinc\tecx\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3466
+#, no-wrap
+msgid ""
+"\tor\tah, ah\n"
+"\tjne\t.openoutput\n"
+"\tpop\tecx\n"
+"\tjecxz\tusage\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3493
+#, no-wrap
+msgid ""
+"\t; Find the path to the input file\n"
+"\tor\tah, ah\n"
+"\tjne\t.openinput\n"
+"\tpop\tecx\n"
+"\tor\tecx, ecx\n"
+"\tje near usage\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3509
+#, no-wrap
+msgid ""
+".p:\n"
+"\tcmp\tal, 'p'\n"
+"\tjne\t.c\n"
+"\tor\tah, ah\n"
+"\tjne\t.pcheck\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3513
+#, no-wrap
+msgid ""
+"\tpop\tecx\n"
+"\tor\tecx, ecx\n"
+"\tje\tnear usage\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3515
+#, no-wrap
+msgid "\tmov\tah, [ecx]\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3523
+#, no-wrap
+msgid ""
+".pcheck:\n"
+"\tcmp\tah, '0'\n"
+"\tjl\tnear usage\n"
+"\tcmp\tah, '9'\n"
+"\tja\tnear usage\n"
+"\tmov\tesi, ecx\n"
+"\tjmp\t.arg\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3531
+#, no-wrap
+msgid ""
+".c:\n"
+"\tcmp\tal, 'c'\n"
+"\tjne\t.b\n"
+"\tor\tah, ah\n"
+"\tjne\tnear usage\n"
+"\tmov\tesi, connors\n"
+"\tjmp\t.arg\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3539
+#, no-wrap
+msgid ""
+".b:\n"
+"\tcmp\tal, 'b'\n"
+"\tjne\t.e\n"
+"\tor\tah, ah\n"
+"\tjne\tnear usage\n"
+"\tmov\tesi, pinhole\n"
+"\tjmp\t.arg\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3552
+#, no-wrap
+msgid ""
+".e:\n"
+"\tcmp\tal, 'e'\n"
+"\tjne\tnear usage\n"
+"\tor\tah, ah\n"
+"\tjne\tnear usage\n"
+"\tmov\tal, ','\n"
+"\tmov\t[huhmsg], al\n"
+"\tmov\t[separ], al\n"
+"\tmov\t[sep2], al\n"
+"\tmov\t[sep3], al\n"
+"\tmov\t[sep4], al\n"
+"\tjmp\t.arg\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3559
+#, no-wrap
+msgid ""
+"align 4\n"
+".getenv:\n"
+"\t; If ESI = 0, we did not have a -p argument,\n"
+"\t; and need to check the environment for \"PINHOLE=\"\n"
+"\tor\tesi, esi\n"
+"\tjne\t.init\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3561
+#, no-wrap
+msgid "\tsub\tecx, ecx\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3566
+#, no-wrap
+msgid ""
+".nextenv:\n"
+"\tpop\tesi\n"
+"\tor\tesi, esi\n"
+"\tje\t.default\t; no PINHOLE envar found\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3572
+#, no-wrap
+msgid ""
+"\t; check if this envar starts with 'PINHOLE='\n"
+"\tmov\tedi, envar\n"
+"\tmov\tcl, 2\t\t; 'PINHOLE=' is 2 dwords long\n"
+"rep\tcmpsd\n"
+"\tjne\t.nextenv\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3580
+#, no-wrap
+msgid ""
+"\t; Check if it is followed by a digit\n"
+"\tmov\tal, [esi]\n"
+"\tcmp\tal, '0'\n"
+"\tjl\t.default\n"
+"\tcmp\tal, '9'\n"
+"\tjbe\t.init\n"
+"\t; fall through\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3587
+#, no-wrap
+msgid ""
+"align 4\n"
+".default:\n"
+"\t; We got here because we had no -p argument,\n"
+"\t; and did not find the PINHOLE envar.\n"
+"\tmov\tesi, pinhole\n"
+"\t; fall through\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3596
+#, no-wrap
+msgid ""
+"align 4\n"
+".init:\n"
+"\tsub\teax, eax\n"
+"\tsub\tebx, ebx\n"
+"\tsub\tecx, ecx\n"
+"\tsub\tedx, edx\n"
+"\tmov\tedi, dbuffer+1\n"
+"\tmov\tbyte [dbuffer], '0'\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3605
+#, no-wrap
+msgid ""
+"\t; Convert the pinhole constant to real\n"
+".constloop:\n"
+"\tlodsb\n"
+"\tcmp\tal, '9'\n"
+"\tja\t.setconst\n"
+"\tcmp\tal, '0'\n"
+"\tje\t.processconst\n"
+"\tjb\t.setconst\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3607
+#, no-wrap
+msgid "\tinc\tdl\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3614
+#, no-wrap
+msgid ""
+".processconst:\n"
+"\tinc\tcl\n"
+"\tcmp\tcl, 18\n"
+"\tja\tnear consttoobig\n"
+"\tstosb\n"
+"\tjmp\tshort .constloop\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3619
+#, no-wrap
+msgid ""
+"align 4\n"
+".setconst:\n"
+"\tor\tdl, dl\n"
+"\tje\tnear perr\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3622
+#, no-wrap
+msgid ""
+"\tfinit\n"
+"\tfild\tdword [tthou]\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3626
+#, no-wrap
+msgid ""
+"\tfld1\n"
+"\tfild\tdword [ten]\n"
+"\tfdivp\tst1, st0\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3629
+#, no-wrap
+msgid ""
+"\tfild\tdword [thousand]\n"
+"\tmov\tedi, obuffer\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3632
+#, no-wrap
+msgid ""
+"\tmov\tebp, ecx\n"
+"\tcall\tbcdload\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3636
+#, no-wrap
+msgid ""
+".constdiv:\n"
+"\tfmul\tst0, st2\n"
+"\tloop\t.constdiv\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3643
+#, no-wrap
+msgid ""
+"\tfld1\n"
+"\tfadd\tst0, st0\n"
+"\tfadd\tst0, st0\n"
+"\tfld1\n"
+"\tfaddp\tst1, st0\n"
+"\tfchs\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3648
+#, no-wrap
+msgid ""
+"\t; If we are creating a CSV file,\n"
+"\t; print header\n"
+"\tcmp\tbyte [separ], ','\n"
+"\tjne\t.bigloop\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3653
+#, no-wrap
+msgid ""
+"\tpush\tdword headlen\n"
+"\tpush\tdword header\n"
+"\tpush\tdword [fd.out]\n"
+"\tsys.write\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3657
+#, no-wrap
+msgid ""
+".bigloop:\n"
+"\tcall\tgetchar\n"
+"\tjc\tnear done\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3663
+#, no-wrap
+msgid ""
+"\t; Skip to the end of the line if you got '#'\n"
+"\tcmp\tal, '#'\n"
+"\tjne\t.num\n"
+"\tcall\tskiptoeol\n"
+"\tjmp\tshort .bigloop\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3670
+#, no-wrap
+msgid ""
+".num:\n"
+"\t; See if you got a number\n"
+"\tcmp\tal, '0'\n"
+"\tjl\t.bigloop\n"
+"\tcmp\tal, '9'\n"
+"\tja\t.bigloop\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3674
+#, no-wrap
+msgid ""
+"\t; Yes, we have a number\n"
+"\tsub\tebp, ebp\n"
+"\tsub\tedx, edx\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3679
+#, no-wrap
+msgid ""
+".number:\n"
+"\tcmp\tal, '0'\n"
+"\tje\t.number0\n"
+"\tmov\tdl, 1\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3690
+#, no-wrap
+msgid ""
+".number0:\n"
+"\tor\tdl, dl\t\t; Skip leading 0's\n"
+"\tje\t.nextnumber\n"
+"\tpush\teax\n"
+"\tcall\tputchar\n"
+"\tpop\teax\n"
+"\tinc\tebp\n"
+"\tcmp\tebp, 19\n"
+"\tjae\t.nextnumber\n"
+"\tmov\t[dbuffer+ebp], al\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3701
+#, no-wrap
+msgid ""
+".nextnumber:\n"
+"\tcall\tgetchar\n"
+"\tjc\t.work\n"
+"\tcmp\tal, '#'\n"
+"\tje\t.ungetc\n"
+"\tcmp\tal, '0'\n"
+"\tjl\t.work\n"
+"\tcmp\tal, '9'\n"
+"\tja\t.work\n"
+"\tjmp\tshort .number\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3705
+#, no-wrap
+msgid ""
+".ungetc:\n"
+"\tdec\tesi\n"
+"\tinc\tebx\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3710
+#, no-wrap
+msgid ""
+".work:\n"
+"\t; Now, do all the work\n"
+"\tor\tdl, dl\n"
+"\tje\tnear .work0\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3713
+#, no-wrap
+msgid ""
+"\tcmp\tebp, 19\n"
+"\tjae\tnear .toobig\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3715
+#, no-wrap
+msgid "\tcall\tbcdload\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3717
+#, no-wrap
+msgid "\t; Calculate pinhole diameter\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3724
+#, no-wrap
+msgid ""
+"\tfld\tst0\t; save it\n"
+"\tfsqrt\n"
+"\tfmul\tst0, st3\n"
+"\tfld\tst0\n"
+"\tfmul\tst5\n"
+"\tsub\tebp, ebp\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3734
+#, no-wrap
+msgid ""
+"\t; Round off to 4 significant digits\n"
+".diameter:\n"
+"\tfcom\tst0, st7\n"
+"\tfstsw\tax\n"
+"\tsahf\n"
+"\tjb\t.printdiameter\n"
+"\tfmul\tst0, st6\n"
+"\tinc\tebp\n"
+"\tjmp\tshort .diameter\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3737
+#, no-wrap
+msgid ""
+".printdiameter:\n"
+"\tcall\tprintnumber\t; pinhole diameter\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3739
+#, no-wrap
+msgid "\t; Calculate F-number\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3742
+#, no-wrap
+msgid ""
+"\tfdivp\tst1, st0\n"
+"\tfld\tst0\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3744
+#, no-wrap
+msgid "\tsub\tebp, ebp\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3753
+#, no-wrap
+msgid ""
+".fnumber:\n"
+"\tfcom\tst0, st6\n"
+"\tfstsw\tax\n"
+"\tsahf\n"
+"\tjb\t.printfnumber\n"
+"\tfmul\tst0, st5\n"
+"\tinc\tebp\n"
+"\tjmp\tshort .fnumber\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3756
+#, no-wrap
+msgid ""
+".printfnumber:\n"
+"\tcall\tprintnumber\t; F number\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3767
+#, no-wrap
+msgid ""
+"\t; Calculate normalized F-number\n"
+"\tfmul\tst0, st0\n"
+"\tfld1\n"
+"\tfld\tst1\n"
+"\tfyl2x\n"
+"\tfrndint\n"
+"\tfld1\n"
+"\tfscale\n"
+"\tfsqrt\n"
+"\tfstp\tst1\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3770
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3798
+#, no-wrap
+msgid ""
+"\tsub\tebp, ebp\n"
+"\tcall\tprintnumber\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3772
+#, no-wrap
+msgid "\t; Calculate time multiplier from F-5.6\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3775
+#, no-wrap
+msgid ""
+"\tfscale\n"
+"\tfld\tst0\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3781
+#, no-wrap
+msgid ""
+"\t; Round off to 4 significant digits\n"
+".fmul:\n"
+"\tfcom\tst0, st6\n"
+"\tfstsw\tax\n"
+"\tsahf\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3786
+#, no-wrap
+msgid ""
+"\tjb\t.printfmul\n"
+"\tinc\tebp\n"
+"\tfmul\tst0, st5\n"
+"\tjmp\tshort .fmul\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3789
+#, no-wrap
+msgid ""
+".printfmul:\n"
+"\tcall\tprintnumber\t; F multiplier\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3791
+#, no-wrap
+msgid "\t; Calculate F-stops from 5.6\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3795
+#, no-wrap
+msgid ""
+"\tfld1\n"
+"\tfxch\tst1\n"
+"\tfyl2x\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3802
+#, no-wrap
+msgid ""
+"\tmov\tal, 0Ah\n"
+"\tcall\tputchar\n"
+"\tjmp\t.bigloop\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3806
+#, no-wrap
+msgid ""
+".work0:\n"
+"\tmov\tal, '0'\n"
+"\tcall\tputchar\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3811
+#, no-wrap
+msgid ""
+"align 4\n"
+".toobig:\n"
+"\tcall\thuh\n"
+"\tjmp\t.bigloop\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3815
+#, no-wrap
+msgid ""
+"align 4\n"
+"done:\n"
+"\tcall\twrite\t\t; flush output buffer\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3824
+#, no-wrap
+msgid "\tfinit\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3837
+#, no-wrap
+msgid ""
+"align 4\n"
+"skiptoeol:\n"
+"\t; Keep reading until you come to cr, lf, or eof\n"
+"\tcall\tgetchar\n"
+"\tjc\tdone\n"
+"\tcmp\tal, 0Ah\n"
+"\tjne\t.cr\n"
+"\tret\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3842
+#, no-wrap
+msgid ""
+".cr:\n"
+"\tcmp\tal, 0Dh\n"
+"\tjne\tskiptoeol\n"
+"\tret\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3855
+#, no-wrap
+msgid ""
+".fetch:\n"
+"\tlodsb\n"
+"\tdec\tebx\n"
+"\tclc\n"
+"\tret\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3872
+#, no-wrap
+msgid ""
+".read:\n"
+"\tpush\tdword BUFSIZE\n"
+"\tmov\tesi, ibuffer\n"
+"\tpush\tesi\n"
+"\tpush\tdword [fd.in]\n"
+"\tsys.read\n"
+"\tadd\tesp, byte 12\n"
+"\tmov\tebx, eax\n"
+"\tor\teax, eax\n"
+"\tje\t.empty\n"
+"\tsub\teax, eax\n"
+"\tret\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3878
+#, no-wrap
+msgid ""
+"align 4\n"
+".empty:\n"
+"\tadd\tesp, byte 4\n"
+"\tstc\n"
+"\tret\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3907
+#, no-wrap
+msgid ""
+"align 4\n"
+"bcdload:\n"
+"\t; EBP contains the number of chars in dbuffer\n"
+"\tpush\tecx\n"
+"\tpush\tesi\n"
+"\tpush\tedi\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3911
+#, no-wrap
+msgid ""
+"\tlea\tecx, [ebp+1]\n"
+"\tlea\tesi, [dbuffer+ebp-1]\n"
+"\tshr\tecx, 1\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3913
+#, no-wrap
+msgid "\tstd\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3919
+#, no-wrap
+msgid ""
+"\tmov\tedi, bbuffer\n"
+"\tsub\teax, eax\n"
+"\tmov\t[edi], eax\n"
+"\tmov\t[edi+4], eax\n"
+"\tmov\t[edi+2], ax\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3928
+#, no-wrap
+msgid ""
+".loop:\n"
+"\tlodsw\n"
+"\tsub\tax, 3030h\n"
+"\tshl\tal, 4\n"
+"\tor\tal, ah\n"
+"\tmov\t[edi], al\n"
+"\tinc\tedi\n"
+"\tloop\t.loop\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3930
+#, no-wrap
+msgid "\tfbld\t[bbuffer]\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3937
+#, no-wrap
+msgid ""
+"\tcld\n"
+"\tpop\tedi\n"
+"\tpop\tesi\n"
+"\tpop\tecx\n"
+"\tsub\teax, eax\n"
+"\tret\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3943
+#, no-wrap
+msgid ""
+"align 4\n"
+"printnumber:\n"
+"\tpush\tebp\n"
+"\tmov\tal, [separ]\n"
+"\tcall\tputchar\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3947
+#, no-wrap
+msgid ""
+"\t; Print the integer at the TOS\n"
+"\tmov\tebp, bbuffer+9\n"
+"\tfbstp\t[bbuffer]\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3953
+#, no-wrap
+msgid ""
+"\t; Check the sign\n"
+"\tmov\tal, [ebp]\n"
+"\tdec\tebp\n"
+"\tor\tal, al\n"
+"\tjns\t.leading\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3957
+#, no-wrap
+msgid ""
+"\t; We got a negative number (should never happen)\n"
+"\tmov\tal, '-'\n"
+"\tcall\tputchar\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3966
+#, no-wrap
+msgid ""
+".leading:\n"
+"\t; Skip leading zeros\n"
+"\tmov\tal, [ebp]\n"
+"\tdec\tebp\n"
+"\tor\tal, al\n"
+"\tjne\t.first\n"
+"\tcmp\tebp, bbuffer\n"
+"\tjae\t.leading\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3971
+#, no-wrap
+msgid ""
+"\t; We are here because the result was 0.\n"
+"\t; Print '0' and return\n"
+"\tmov\tal, '0'\n"
+"\tjmp\tputchar\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3983
+#, no-wrap
+msgid ""
+".first:\n"
+"\t; We have found the first non-zero.\n"
+"\t; But it is still packed\n"
+"\ttest\tal, 0F0h\n"
+"\tjz\t.second\n"
+"\tpush\teax\n"
+"\tshr\tal, 4\n"
+"\tadd\tal, '0'\n"
+"\tcall\tputchar\n"
+"\tpop\teax\n"
+"\tand\tal, 0Fh\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3987
+#, no-wrap
+msgid ""
+".second:\n"
+"\tadd\tal, '0'\n"
+"\tcall\tputchar\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:3991
+#, no-wrap
+msgid ""
+".next:\n"
+"\tcmp\tebp, bbuffer\n"
+"\tjb\t.done\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4001
+#, no-wrap
+msgid ""
+"\tmov\tal, [ebp]\n"
+"\tpush\teax\n"
+"\tshr\tal, 4\n"
+"\tadd\tal, '0'\n"
+"\tcall\tputchar\n"
+"\tpop\teax\n"
+"\tand\tal, 0Fh\n"
+"\tadd\tal, '0'\n"
+"\tcall\tputchar\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4004
+#, no-wrap
+msgid ""
+"\tdec\tebp\n"
+"\tjmp\tshort .next\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4009
+#, no-wrap
+msgid ""
+".done:\n"
+"\tpop\tebp\n"
+"\tor\tebp, ebp\n"
+"\tje\t.ret\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4015
+#, no-wrap
+msgid ""
+".zeros:\n"
+"\tmov\tal, '0'\n"
+"\tcall\tputchar\n"
+"\tdec\tebp\n"
+"\tjne\t.zeros\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4018
+#, no-wrap
+msgid ""
+".ret:\n"
+"\tret\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4021
+msgid ""
+"The code follows the same format as all the other filters we have seen "
+"before, with one subtle exception:"
+msgstr ""
+
+#. type: delimited block _ 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4024
+msgid ""
+"We are no longer assuming that the end of input implies the end of things to "
+"do, something we took for granted in the _character-oriented_ filters."
+msgstr ""
+
+#. type: delimited block _ 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4026
+msgid ""
+"This filter does not process characters. It processes a _language_ (albeit a "
+"very simple one, consisting only of numbers)."
+msgstr ""
+
+#. type: delimited block _ 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4028
+msgid "When we have no more input, it can mean one of two things:"
+msgstr ""
+
+#. type: delimited block _ 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4030
+msgid "We are done and can quit. This is the same as before."
+msgstr ""
+
+#. type: delimited block _ 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4031
+msgid ""
+"The last character we have read was a digit. We have stored it at the end of "
+"our ASCII-to-float conversion buffer. We now need to convert the contents of "
+"that buffer into a number and write the last line of our output."
+msgstr ""
+
+#. type: delimited block _ 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4033
+msgid ""
+"For that reason, we have modified our `getchar` and our `read` routines to "
+"return with the `carry flag` _clear_ whenever we are fetching another "
+"character from the input, or the `carry flag` _set_ whenever there is no "
+"more input."
+msgstr ""
+
+#. type: delimited block _ 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4036
+msgid ""
+"Of course, we are still using assembly language magic to do that! Take a "
+"good look at `getchar`. It _always_ returns with the `carry flag` _clear_."
+msgstr ""
+
+#. type: delimited block _ 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4038
+msgid ""
+"Yet, our main code relies on the `carry flag` to tell it when to quit-and it "
+"works."
+msgstr ""
+
+#. type: delimited block _ 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4041
+msgid ""
+"The magic is in `read`. Whenever it receives more input from the system, it "
+"just returns to `getchar`, which fetches a character from the input buffer, "
+"_clears_ the `carry flag` and returns."
+msgstr ""
+
+#. type: delimited block _ 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4044
+msgid ""
+"But when `read` receives no more input from the system, it does _not_ return "
+"to `getchar` at all. Instead, the `add esp, byte 4` op code adds `4` to "
+"`ESP`, _sets_ the `carry flag`, and returns."
+msgstr ""
+
+#. type: delimited block _ 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4048
+msgid ""
+"So, where does it return to? Whenever a program uses the `call` op code, the "
+"microprocessor ``push``es the return address, i.e., it stores it on the top "
+"of the stack (not the FPU stack, the system stack, which is in the memory). "
+"When a program uses the `ret` op code, the microprocessor ``pop``s the "
+"return value from the stack, and jumps to the address that was stored there."
+msgstr ""
+
+#. type: delimited block _ 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4050
+msgid ""
+"But since we added `4` to `ESP` (which is the stack pointer register), we "
+"have effectively given the microprocessor a minor case of _amnesia_: It no "
+"longer remembers it was `getchar` that ``call``ed `read`."
+msgstr ""
+
+#. type: delimited block _ 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4052
+msgid ""
+"And since `getchar` never ``push``ed anything before ``call``ing `read`, the "
+"top of the stack now contains the return address to whatever or whoever "
+"``call``ed `getchar`. As far as that caller is concerned, he ``call``ed "
+"`getchar`, which ``ret``urned with the `carry flag` set!"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4055
+msgid ""
+"Other than that, the `bcdload` routine is caught up in the middle of a "
+"Lilliputian conflict between the Big-Endians and the Little-Endians."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4057
+msgid ""
+"It is converting the text representation of a number into that number: The "
+"text is stored in the big-endian order, but the _packed decimal_ is little-"
+"endian."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4060
+msgid ""
+"To solve the conflict, we use the `std` op code early on. We cancel it with "
+"`cld` later on: It is quite important we do not `call` anything that may "
+"depend on the default setting of the _direction flag_ while `std` is active."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4062
+msgid ""
+"Everything else in this code should be quit eclear, providing you have read "
+"the entire chapter that precedes it."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4065
+msgid ""
+"It is a classical example of the adage that programming requires a lot of "
+"thought and only a little coding. Once we have thought through every tiny "
+"detail, the code almost writes itself."
+msgstr ""
+
+#. type: Title ===
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4067
+#, no-wrap
+msgid "Using pinhole"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4071
+msgid ""
+"Because we have decided to make the program _ignore_ any input except for "
+"numbers (and even those inside a comment), we can actually perform _textual "
+"queries_. We do not _have to_, but we _can_."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4073
+msgid ""
+"In my humble opinion, forming a textual query, instead of having to follow a "
+"very strict syntax, makes software much more user friendly."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4079
+msgid ""
+"Suppose we want to build a pinhole camera to use the 4x5 inch film. The "
+"standard focal length for that film is about 150mm. We want to _fine-tune_ "
+"our focal length so the pinhole diameter is as round a number as possible. "
+"Let us also suppose we are quite comfortable with cameras but somewhat "
+"intimidated by computers. Rather than just have to type in a bunch of "
+"numbers, we want to _ask_ a couple of questions."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4081
+msgid "Our session might look like this:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4085
+#, no-wrap
+msgid "% pinhole\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4087
+#, no-wrap
+msgid "Computer,\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4100
+#, no-wrap
+msgid ""
+"What size pinhole do I need for the focal length of 150?\n"
+"150\t490\t306\t362\t2930\t12\n"
+"Hmmm... How about 160?\n"
+"160\t506\t316\t362\t3125\t12\n"
+"Let's make it 155, please.\n"
+"155\t498\t311\t362\t3027\t12\n"
+"Ah, let's try 157...\n"
+"157\t501\t313\t362\t3066\t12\n"
+"156?\n"
+"156\t500\t312\t362\t3047\t12\n"
+"That's it! Perfect! Thank you very much!\n"
+"^D\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4103
+msgid ""
+"We have found that while for the focal length of 150, our pinhole diameter "
+"should be 490 microns, or 0.49 mm, if we go with the almost identical focal "
+"length of 156 mm, we can get away with a pinhole diameter of exactly one "
+"half of a millimeter."
+msgstr ""
+
+#. type: Title ===
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4105
+#, no-wrap
+msgid "Scripting"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4108
+msgid ""
+"Because we have chosen the `+#+` character to denote the start of a comment, "
+"we can treat our pinhole software as a _scripting language_."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4110
+msgid "You have probably seen shell _scripts_ that start with:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4114
+#, no-wrap
+msgid "#! /bin/sh\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4117
+msgid "...or..."
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4121
+#, no-wrap
+msgid "#!/bin/sh\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4124
+msgid "...because the blank space after the `#!` is optional."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4127
+msgid ""
+"Whenever UNIX(R) is asked to run an executable file which starts with the `#!"
+"`, it assumes the file is a script. It adds the command to the rest of the "
+"first line of the script, and tries to execute that."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4129
+msgid ""
+"Suppose now that we have installed pinhole in /usr/local/bin/, we can now "
+"write a script to calculate various pinhole diameters suitable for various "
+"focal lengths commonly used with the 120 film."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4131
+msgid "The script might look something like this:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4137
+#, no-wrap
+msgid ""
+"#! /usr/local/bin/pinhole -b -i\n"
+"# Find the best pinhole diameter\n"
+"# for the 120 film\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4140
+#, no-wrap
+msgid ""
+"### Standard\n"
+"80\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4143
+#, no-wrap
+msgid ""
+"### Wide angle\n"
+"30, 40, 50, 60, 70\n"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4146
+#, no-wrap
+msgid ""
+"### Telephoto\n"
+"100, 120, 140\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4149
+msgid "Because 120 is a medium size film, we may name this file medium."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4151
+msgid ""
+"We can set its permissions to execute, and run it as if it were a program:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4156
+#, no-wrap
+msgid ""
+"% chmod 755 medium\n"
+"% ./medium\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4159
+msgid "UNIX(R) will interpret that last command as:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4163
+#, no-wrap
+msgid "% /usr/local/bin/pinhole -b -i ./medium\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4166
+msgid "It will run that command and display:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4178
+#, no-wrap
+msgid ""
+"80\t358\t224\t256\t1562\t11\n"
+"30\t219\t137\t128\t586\t9\n"
+"40\t253\t158\t181\t781\t10\n"
+"50\t283\t177\t181\t977\t10\n"
+"60\t310\t194\t181\t1172\t10\n"
+"70\t335\t209\t181\t1367\t10\n"
+"100\t400\t250\t256\t1953\t11\n"
+"120\t438\t274\t256\t2344\t11\n"
+"140\t473\t296\t256\t2734\t11\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4181
+msgid "Now, let us enter:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4185
+#, no-wrap
+msgid "% ./medium -c\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4188
+msgid "UNIX(R) will treat that as:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4192
+#, no-wrap
+msgid "% /usr/local/bin/pinhole -b -i ./medium -c\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4196
+msgid ""
+"That gives it two conflicting options: `-b` and `-c` (Use Bender's constant "
+"and use Connors' constant). We have programmed it so later options override "
+"early ones-our program will calculate everything using Connors' constant:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4208
+#, no-wrap
+msgid ""
+"80\t331\t242\t256\t1826\t11\n"
+"30\t203\t148\t128\t685\t9\n"
+"40\t234\t171\t181\t913\t10\n"
+"50\t262\t191\t181\t1141\t10\n"
+"60\t287\t209\t181\t1370\t10\n"
+"70\t310\t226\t256\t1598\t11\n"
+"100\t370\t270\t256\t2283\t11\n"
+"120\t405\t296\t256\t2739\t11\n"
+"140\t438\t320\t362\t3196\t12\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4212
+msgid ""
+"We decide we want to go with Bender's constant after all. We want to save "
+"its values as a comma-separated file:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4228
+#, no-wrap
+msgid ""
+"% ./medium -b -e > bender\n"
+"% cat bender\n"
+"focal length in millimeters,pinhole diameter in microns,F-number,normalized F-number,F-5.6 multiplier,stops from F-5.6\n"
+"80,358,224,256,1562,11\n"
+"30,219,137,128,586,9\n"
+"40,253,158,181,781,10\n"
+"50,283,177,181,977,10\n"
+"60,310,194,181,1172,10\n"
+"70,335,209,181,1367,10\n"
+"100,400,250,256,1953,11\n"
+"120,438,274,256,2344,11\n"
+"140,473,296,256,2734,11\n"
+"%\n"
+msgstr ""
+
+#. type: Title ==
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4231
+#, no-wrap
+msgid "Caveats"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4235
+msgid ""
+"Assembly language programmers who \"grew up\" under MS-DOS(R) and Windows(R) "
+"often tend to take shortcuts. Reading the keyboard scan codes and writing "
+"directly to video memory are two classical examples of practices which, "
+"under MS-DOS(R) are not frowned upon but considered the right thing to do."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4237
+msgid ""
+"The reason? Both the PC BIOS and MS-DOS(R) are notoriously slow when "
+"performing these operations."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4240
+msgid ""
+"You may be tempted to continue similar practices in the UNIX(R) "
+"environment. For example, I have seen a web site which explains how to "
+"access the keyboard scan codes on a popular UNIX(R) clone."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4242
+msgid ""
+"That is generally a _very bad idea_ in UNIX(R) environment! Let me explain "
+"why."
+msgstr ""
+
+#. type: Title ===
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4244
+#, no-wrap
+msgid "UNIX(R) Is Protected"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4251
+msgid ""
+"For one thing, it may simply not be possible. UNIX(R) runs in protected "
+"mode. Only the kernel and device drivers are allowed to access hardware "
+"directly. Perhaps a particular UNIX(R) clone will let you read the keyboard "
+"scan codes, but chances are a real UNIX(R) operating system will not. And "
+"even if one version may let you do it, the next one may not, so your "
+"carefully crafted software may become a dinosaur overnight."
+msgstr ""
+
+#. type: Title ===
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4253
+#, no-wrap
+msgid "UNIX(R) Is an Abstraction"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4256
+msgid ""
+"But there is a much more important reason not to try accessing the hardware "
+"directly (unless, of course, you are writing a device driver), even on the "
+"UNIX(R) like systems that let you do it:"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4258
+msgid "_UNIX(R) is an abstraction!_"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4264
+msgid ""
+"There is a major difference in the philosophy of design between MS-DOS(R) "
+"and UNIX(R). MS-DOS(R) was designed as a single-user system. It is run on "
+"a computer with a keyboard and a video screen attached directly to that "
+"computer. User input is almost guaranteed to come from that keyboard. Your "
+"program's output virtually always ends up on that screen."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4267
+msgid ""
+"This is NEVER guaranteed under UNIX(R). It is quite common for a UNIX(R) "
+"user to pipe and redirect program input and output:"
+msgstr ""
+
+#. type: delimited block . 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4271
+#, no-wrap
+msgid "% program1 | program2 | program3 > file1\n"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4275
+msgid ""
+"If you have written program2, your input does not come from the keyboard but "
+"from the output of program1. Similarly, your output does not go to the "
+"screen but becomes the input for program3 whose output, in turn, goes to [."
+"filename]#file1#."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4278
+msgid ""
+"But there is more! Even if you made sure that your input comes from, and "
+"your output goes to, the terminal, there is no guarantee the terminal is a "
+"PC: It may not have its video memory where you expect it, nor may its "
+"keyboard be producing PC-style scan codes. It may be a Macintosh(R), or any "
+"other computer."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4280
+msgid ""
+"Now you may be shaking your head: My software is in PC assembly language, "
+"how can it run on a Macintosh(R)? But I did not say your software would be "
+"running on a Macintosh(R), only that its terminal may be a Macintosh(R)."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4284
+msgid ""
+"Under UNIX(R), the terminal does not have to be directly attached to the "
+"computer that runs your software, it can even be on another continent, or, "
+"for that matter, on another planet. It is perfectly possible that a "
+"Macintosh(R) user in Australia connects to a UNIX(R) system in North America "
+"(or anywhere else) via telnet. The software then runs on one computer, "
+"while the terminal is on a different computer: If you try to read the scan "
+"codes, you will get the wrong input!"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4287
+msgid ""
+"Same holds true about any other hardware: A file you are reading may be on a "
+"disk you have no direct access to. A camera you are reading images from may "
+"be on a space shuttle, connected to you via satellites."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4290
+msgid ""
+"That is why under UNIX(R) you must never make any assumptions about where "
+"your data is coming from and going to. Always let the system handle the "
+"physical access to the hardware."
+msgstr ""
+
+#. type: delimited block = 4
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4298
+msgid ""
+"These are caveats, not absolute rules. Exceptions are possible. For "
+"example, if a text editor has determined it is running on a local machine, "
+"it may want to read the scan codes directly for improved control. I am not "
+"mentioning these caveats to tell you what to do or what not to do, just to "
+"make you aware of certain pitfalls that await you if you have just arrived "
+"to UNIX(R) form MS-DOS(R). Of course, creative people often break rules, "
+"and it is OK as long as they know they are breaking them and why."
+msgstr ""
+
+#. type: Title ==
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4301
+#, no-wrap
+msgid "Acknowledgements"
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4304
+msgid ""
+"This tutorial would never have been possible without the help of many "
+"experienced FreeBSD programmers from the {freebsd-hackers}, many of whom "
+"have patiently answered my questions, and pointed me in the right direction "
+"in my attempts to explore the inner workings of UNIX(R) system programming "
+"in general and FreeBSD in particular."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4307
+msgid ""
+"Thomas M. Sommers opened the door for me . His https://web.archive.org/"
+"web/20090914064615/http://www.codebreakers-journal.com/content/"
+"view/262/27[How do I write \"Hello, world\" in FreeBSD assembler?] web page "
+"was my first encounter with an example of assembly language programming "
+"under FreeBSD."
+msgstr ""
+
+#. type: Plain text
+#: documentation/content/en/books/developers-handbook/x86/_index.adoc:4309
+msgid ""
+"Jake Burkholder has kept the door open by willingly answering all of my "
+"questions and supplying me with example assembly language source code."
+msgstr ""