- •Table of Contents
- •Foreword
- •Do Not Pass GO
- •Counting in Martian
- •Octal: How the Grinch Stole Eight and Nine
- •Hexadecimal: Solving the Digit Shortage
- •From Hex to Decimal and from Decimal to Hex
- •Arithmetic in Hex
- •Binary
- •Hexadecimal as Shorthand for Binary
- •Switches, Transistors, and Memory
- •The Shop Foreman and the Assembly Line
- •The Box That Follows a Plan
- •DOS and DOS files
- •Compilers and Assemblers
- •The Assembly Language Development Process
- •DEBUG and How to Use It
- •Chapter 5: NASM-IDE: A Place to Stand Give me a lever long enough, and a place to stand, and I will move the Earth.
- •NASM-IDE's Place to Stand
- •Using NASM-IDE's Tools
- •NASM-IDE's Editor in Detail
- •Other NASM-IDE Features
- •The Nature of Segments
- •16-Bit and 32-Bit Registers
- •The Three Major Assembly Programming Models
- •Reading and Changing Registers with DEBUG
- •Assembling and Executing Machine Instructions with DEBUG
- •Machine Instructions and Their Operands
- •Reading and Using an Assembly Language Reference
- •Rally Round the Flags, Boys!
- •Using Type Specifiers
- •The Bones of an Assembly Language Program
- •Assembling and Running EAT.ASM
- •One Program, Three Segments
- •Last In, First Out via the Stack
- •Using DOS Services through INT
- •Boxes within Boxes
- •Using BIOS Services
- •Building External Libraries of Procedures
- •Creating and Using Macros
- •Bits Is Bits (and Bytes Is Bits)
- •Shifting Bits
- •Flags, Tests, and Branches
- •Assembly Odds 'n Ends
- •The Notion of an Assembly Language String
- •REP STOSW, the Software Machine Gun
- •The Semiautomatic Weapon: STOSW without REP
- •Storing Data to Discontinuous Strings
- •Chapter 12: The Programmer's View of Linux Tools and Skills to Help You Write Assembly Code under a True 32-Bit OS
- •Prerequisites-Yukkh!
- •NASM for Linux
- •What's GNU?
- •The make Utility and Dependencies
- •Using the GNU Debugger
- •Your Work Strategy
- •Genuflecting to the C Culture
- •A Framework to Build On
- •The Perks of Protected Mode
- •Characters Out
- •Characters In
- •Be a Time Lord
- •Generating Random Numbers
- •Accessing Command-Line Arguments
- •Simple File I/O
- •Conclusion: Not the End, But Only the Beginning
- •Where to Now?
- •Stepping off Square One
- •Notes on the Instruction Set Reference
- •AAA Adjust AL after BCD Addition
- •ADC Arithmetic Addition with Carry
- •ADD Arithmetic Addition
- •AND Logical AND
- •BT Bit Test (386+)
- •CALL Call Procedure
- •CLC Clear Carry Flag (CF)
- •CLD Clear Direction Flag (DF)
- •CMP Arithmetic Comparison
- •DEC Decrement Operand
- •IMUL Signed Integer Multiplication
- •INC Increment Operand
- •INT Software Interrupt
- •IRET Return from Interrupt
- •J? Jump on Condition
- •JMP Unconditional Jump
- •LEA Load Effective Address
- •MOV Move (Copy) Right Operand into Left Operand
- •NOP No Operation
- •NOT Logical NOT (One's Complement)
- •OR Logical OR
- •POP Pop Top of Stack into Operand
- •POPA Pop All 16-Bit Registers (286+)
- •POPF Pop Top of Stack into Flags
- •POPFD Pop Top of Stack into EFlags (386+)
- •PUSH Push Operand onto Top of Stack
- •PUSHA Push All 16-Bit GP Registers (286+)
- •PUSHAD Push All 32-Bit GP Registers (386+)
- •PUSHF Push 16-Bit Flags onto Stack
- •PUSHFD Push 32-Bit EFlags onto Stack (386+)
- •RET Return from Procedure
- •ROL Rotate Left
- •ROR Rotate Right
- •SBB Arithmetic Subtraction with Borrow
- •SHL Shift Left
- •SHR Shift Right
- •STC Set Carry Flag (CF)
- •STD Set Direction Flag (DF)
- •STOS Store String
- •SUB Arithmetic Subtraction
- •XCHG Exchange Operands
- •XOR Exclusive Or
- •Appendix C: Web URLs for Assembly Programmers
- •Appendix D: Segment Register Assumptions
- •Appendix E: What's on the CD-ROM?
- •Index
- •List of Figures
- •List of Tables
Binary
Hexadecimal is excellent practice for taking on the strangest number base of all: binary. Binary is base 2. Given what we've learned about number bases so far, what can we surmise about base 2?
Each column has a value two times the column to its right.
There are only two digits (0 and 1) in the base.
Counting is a little strange in binary, as you might imagine. It goes like this: 0, 1, 10, 11, 100, 101, 110, 111, 1,000 … Because it sounds absurd to say, "Zero, one, 10, 11, 100,…" it makes more sense to simply enunciate the individual digits, followed by the word binary. For example, most people say "one zero one one one zero one binary" instead of "one million, eleven thousand, one hundred one binary" when pronouncing the number 1011101—which sounds enormous until you consider that its value in decimal is only 93.
Odd as it may seem, binary follows all of the same rules we've discussed in this chapter regarding number bases. Converting between binary and decimal is done using the same methods described for hexadecimal in an earlier section of this chapter.
Because counting in binary is as much a matter of counting columns as counting digits (since there are only two digits) it makes sense to take a long, close look at Table 2.7, which shows the values of the binary number columns out to 32 places.
Table 2.7: Binary Columns as Powers of 2
BINARY
1
10
100
1000
10000
100000
1000000
10000000
100000000
1000000000
10000000000
100000000000
1000000000000
10000000000000
100000000000000
1000000000000000
10000000000000000
100000000000000000
1000000000000000000
10000000000000000000
100000000000000000000
1000000000000000000000
10000000000000000000000
POWER OF 2 |
|
DECIMAL |
|
|
|
=20= |
|
1 |
|
|
|
=21= |
|
2 |
|
|
|
=22= |
|
4 |
|
|
|
=23= |
|
8 |
|
|
|
=24= |
|
16 |
|
|
|
=25= |
|
32 |
|
|
|
=26= |
|
64 |
|
|
|
=27= |
|
128 |
|
|
|
=28= |
|
256 |
|
|
|
=29= |
|
512 |
|
|
|
=210= |
|
1024 |
|
|
|
=211= |
|
2048 |
|
|
|
=212= |
|
4096 |
|
|
|
=213= |
|
8192 |
|
|
|
=214= |
|
16384 |
|
|
|
=215= |
|
32768 |
|
|
|
=216= |
|
65536 |
|
|
|
=217= |
|
131072 |
|
|
|
=218= |
|
262144 |
|
|
|
=219= |
|
524288 |
|
|
|
=220= |
|
1048576 |
|
|
|
=221= |
|
2097152 |
|
|
|
=222= |
|
4194304 |
|
|
|
|
|
|
|
|
100000000000000000000000 |
|
=223= |
|
8388608 |
|
|
|
|
|
|
||
|
1000000000000000000000000 |
|
=224= |
|
16777216 |
|
|
|
|
|
|
||
|
10000000000000000000000000 |
|
=225= |
|
33554432 |
|
|
|
|
|
|
||
|
100000000000000000000000000 |
|
=226= |
|
67108864 |
|
|
|
|
|
|
||
|
1000000000000000000000000000 |
|
=227= |
|
134217728 |
|
|
|
|
|
|
||
|
10000000000000000000000000000 |
|
=228= |
|
268435456 |
|
|
|
|
|
|
||
|
100000000000000000000000000000 |
|
=229= |
|
536870912 |
|
|
|
|
|
|
||
|
1000000000000000000000000000000 |
|
=230= |
|
1073741824 |
|
|
|
|
|
|
||
|
10000000000000000000000000000000 |
|
=231= |
|
2147483648 |
|
|
|
|
|
|
||
|
100000000000000000000000000000000 |
|
=232= |
|
4294967296 |
|
|
|
|
|
|
|
|
One look at that imposing pyramid of zeroes implies that it's hopeless to think of pronouncing the larger columns as strings of digits: "One zero zero zero zero zero zero zero…" and so on. There's a crying need for a shorthand notation here, so I'll provide you with one in a little while—and its identity will surprise you.
You might object that such large numbers as the bottommost in the table aren't likely to be encountered in ordinary programming. Sorry, but a 32-bit microprocessor such as the Pentium (and even its antiquated forbears like the 386 and 496) can swallow numbers like that in one electrical gulp, and eat billions of them for lunch.You must become accustomed to thinking in terms of such numbers as 232, which, after all, is only a trifling 4 billion in decimal. Think for a moment of the capacity of the hard drive on your own desktop computer. New PCs in the spring of 2000 are routinely shipped with 10 gigabytes or more of hard disk storage. A gigabyte is a billion bytes…so that monster 32-bit number can't even count all the bytes on your hard drive! This little problem has actually bitten some vendors of old (no, sorry, the word is legacy) software. Ten or 12 years ago, a 6-gigabyte hard drive seemed like a distant fantasy for most of us. Now CompUSA sells that fantasy for $129.95. And I have a file utility that throws up its hands in despair any time it has to confront a disk drive with more than 2 gigabytes of free space…
Now, just as with octal and hexadecimal, there can be identity problems when using binary. The number 101 in binary is not the same as 101 in hex, or 101 in decimal. For this reason, always append the suffix "B" to your binary values to make sure people reading your programs (including you, six weeks after the fact) know what base you're working from.
Values in Binary
Converting a value in binary to one in decimal is done the same way it's done in hex—more simply, in fact, for the simple reason that you no longer have to count how many times a column's value is present in any given column. In hex, you have to see how many 16s are present in the 16s column, and so on. In binary, a column's value is either present (1 time) or not present (0 times).
Running through a simple example should make this clear. The binary number 11011010B is a relatively typical binary value in small-time computer work. (On the small side, actually—many common binary numbers are twice its size or more.) Converting 11011010B to decimal comes down to scanning it from right to left with the help of Table 2.7, and tallying any column's value where that column contains a 1, while ignoring any column containing a 0.
Clear your calculator and let's get started:
1.Column 0 contains a 0; skip it.
2.Column 1 contains a 1. That means its value, 2, is present in the value of the number. So we punch 2 into the calculator.
3.Column 2 is 0. Skip it.
4.Column 3 contains a 1. The column's value is 23, or 8; add 8 to our tally.
5.
3.
4.
5.Column 4 also contains a 1; 24 is 16, which we add to our tally.
6.Column 5 is 0. Skip it.
7.Column 6 contains a 1; 26 is 64, so add 64 to the tally.
8.Column 7 also contains a 1. Column 7's value is 27, or 128. Add 128 to the tally, and what do we have? 218. That's the decimal value of 11011010B. It's as easy as that.
Converting from decimal to binary, while more difficult, is done exactly the same way as converting from decimal to hex. Go back and read that section again, searching for the general method used. In other words, see what was done and separate the essential principles from any references to a specific base like hex.
I'll bet by now you can figure it out without much trouble.
As a brief aside, perhaps you noticed that I started counting columns from 0 rather than 1. A peculiarity of the computer field is that we always begin counting things from 0. Actually, to call it a peculiarity is unfair; the computer's method is the reasonable one, because 0 is a perfectly good number and should not be discriminated against. The rift occurred because in our real, physical world, counting things tells us how many things are there, while in the computer world counting things is more generally done to name them. That is, we need to deal with bit number 0, and then bit number 1, and so on, far more than we need to know how many bits there are.
This is not a quibble, by the way. The issue will come up again and again in connection with memory addresses, which as I have said and will say again are the key to understanding assembly language.
In programming circles, always begin counting from 0!
A practical example of the conflicts this principle can cause grows out of the following question: What year begins the new millennium? Most people would intuitively say the year 2000, but technically, the twentieth century will continue until January 1, 2001. Why? Because there was no year 0. When historians count the years moving from B.C. to A.D., they go 1B.C. to 1A.D. Therefore, the first century began with year 1 and ended with year 100. The second century began with year 101 and ended with year 200. By extending the sequence you can see that the twentieth century began in 1901 and will end in 2000. On the other hand, if we had had the sense to begin counting years in the current era computer style, from year 0, the twentieth century would end at the end of 1999. My suggestion? Call this the Short Century (which it certainly seems to those of us who have been around for any considerable chunk of it) and begin the Computer Millennium on January 1, 2000.
This is a good point to get some practice in converting numbers from binary to decimal and back. Sharpen your teeth on these:
110
10001
11111
11
101
1100010111010010
11000
1011
When that's done, convert these decimal values to binary:
77
42
106
255
18
6309
121
58
18,446
Why Binary?
If it takes eight whole digits (11011010) to represent an ordinary three-digit number such as 218, binary as a number base would seem to be a bad intellectual investment. Certainly for us it would be a waste of mental bandwidth, and even aliens with only two fingers would probably have come up with a better system.
The problem is, lights are either on or they're off.
This is just another way of saying (as I discuss in detail in Chapter 3) that at the bottom of it, computers are electrical devices. In an electrical device, voltage is either present or it isn't; current either flows or it doesn't. Very early in the game, computer scientists decided that the presence of a voltage in a computer circuit would indicate a 1 digit, while lack of a voltage at that same point in the circuit would indicate a 0 digit. This isn't many digits, but it's enough for the binary number system. This is the only reason we use binary, but it's a pretty compelling one, and we're stuck with it. However, you will not necessarily drown in ones and zeroes, because I've already taught you a form of shorthand.