Assembly language, put simply, is a human-readable analog of the actual machine operation codes (opcodes) which the CPU actually performs. Assembly language instructions have nearly a one-to-one relationship to the opcodes they represent, though some instructions represent more than one opcode, and some opcodes have more than one instruction name. For example,
MOV AX, FF01h ; copy the number FF01 hex (65281 decimal) into register AX
would be translated into (in hexidecimal):
B8 01 FF
"B8" being the opcode for "Move the next two bytes into register AX". Since the x86 is a little-endian processor (it moves to least significant byte first, then the next higher, and so forth), the assembler automagically reverses order of the bytes in the data word. (if none of this is making sense yet, don't worry; it will become clearer in time).
Just about any assembler (the program which translates the instructions into the binary opcodes) will also allow you to define symbolic labels (names for memory locations) and set aside memory for variables, as well. They also take what are called 'directives', which indicate how it should assemble the code (similar to pragmas, but more integral to the assembly process). Finally, most have a macro preprocessor of some kind.
Netwide Assembler (NASM) is the most popular assembler for x86 systems right now. Others include gas (Gnu Assembler), [http://fasm.sourceforge.net/]Flat Assembler[/url] (FASM), MS Macro Assembler (MASM), and Turbo Assembler (TASM). The first three are probably the ones you'll want to choose from. Most of these use some variant of the syntax Intel originally defined for 8086 family, but gas used the more general AT&T syntax, which is used by Unix and related systems on just about every other platform but is rarely seen in x86 circles. Which one you use is up to you, but NASM is what most people on this board use and is the lingua franca of x86 programming these days.
Assembly is at once both easier and harder than other forms of programming; while assembly instructions are all quite simple, you have to know the details of the computer and the operating system you are using, and even medium-sized programs can be very long and difficult to debug. Learning assembly will give you considerable insight into the behavior of high-level programming languages, as it is, in a sense, what the compiler has to turn a program in (for example) C++ into.
If you intend to write an OS, you
must use a certain amount of assembly language, as there are a handful of necessary operations which can only be written in assembly. If you use a high-level language, you'll also need to learn certain details of how the compiler you are using generates code, particularly how it passes function areguments and return values.
Some of the folks here will tell you that all you have to do is learn the instruction mnemonics, and you'll have assembly programming down. If only it were that simple; the instructions are actually the easy part. On the x86, the really difficult stuff comes from understanding the memory segmentation system, which is rather odd and hard to get a grasp on. It is not impossible, however, and Duntemann's book (see below) explains it quite well.
I usually advise newcomers to the art to buy a copy of Jeff Duntemann's
Assembly Language Step by Step, second ed., as it is the best beginner's book on the subject I've found so far (the web site also has some useful links, as well). There are a number of good sites on the web about assembly programming, as well. A few to try are:
x86 Assembly Language FAQ for comp.lang.asm.x86
Gavin's Guide to 80x86 Assembly
Assembly Language Tutorial
PC Assembly Language Page
Paul Hsieh's Assembly Language Page (Paul is one of the Gurus of x86 assembly, and the page has oodles of good links)
Assembly Language (x86) Resources
and finally,
The Jargon File - ok, so it's not directly relevant, but I
always recommend it, so why stop now?