ch1 - Introduction
1.1 - The Purpose of the Book p1 - ...
ch2 - The Truth about computers p9 - shocking truth: computers are really, really stupid - ... 2.1 - What Computers Can Do
... - computers can a) do basic integer arithmetics b) do memory access c) compare values d) change the order of instruction execution based on a previous comparison - p10 - but can do it very fast, over a
billion instructions per second - ... 2.3 - Basic Computer Organization p11 - basic parts:
• the CPU (also referred to as the processor or microprocessor)
• working memory
• permanent storage
• system bus
... 2.4 - How Computers See Data p12 - numbers ... different voltages ... 1 and 0 ... binary digit ... bit - 0.0 1.1 2.10 3.11 4.100 5.101 6.110 7.111 8.1000 9.1001 10.1010 11. 1011 12.1100 ... stored in circuits on computer/stick etc. - byte = 8 bits, can store number between 0 and 255, in bits: 11111111 - ... gigabytes
RAM ... 64-bit is number between 0 and 18,446,744,073,709,551,615 - ... p16 - ... 2.6 Referring to Memory
... p17 - ... - 1 byte = 8 bits = byte - 2 bytes = 16 bits = word or short - 4 bytes = 32 bits = double-word or int - 8 bytes = 64 bits = quadword - ... p18 - figure 2.1 - 32 bytes ... 2.7 The Structure of the CPU
parts: • registers • control unit • arithmetic and logic unit • memory management unit • caches
... p20 - 2.8 - The Fetch-Execute Cycle
Part I - Assembly Language Basics ch3 - Your First Program p25 - ... 3.1 - Building a Simple Assembly Language Program
First program we build does nothing but exit with a status code - don’t worry yet about how it works - goal is to just get something entered and worked through the process - type file myexit.s using an editor - will discuss line by line in next section - 3.1_myexit.s# My first program. This is a comment.
movq $60, %rax
movq $44, %rdi
syscall # in 32-bit assembly: int 0x80
# LPA p26 - assemble: as myexit.s -o myexit.o # myexit.o = object file, not yet runnable
# link: ld myexit.o -o myexit
# run: ./myexit # executable file
# echo $? #> output: 44p26 - source code, gets assembled into machine code (has same meaning as source code) using assembler (GNU Assembler, as) - does nothing but exit - and leaves exit status code, accessable with echo $?
... p32 - ... Exercises
... - 4. Read through Appendix C - see if you can run your program a step at a time under the debugger gdb (GNU debugger) - not working ... -
GNU_Debugger - WP Debugging assembly with GDB - ncona.com
#> (gdb) _
file myexitch4 - Registers and Simple Arithmetic p33 - ... - On x86-64, arithmetic instructions only have two operands - the second operand has two functions - it operates as both part of the arithmetic and is also the destination where the result is stored - for instance, let’s say that we wanted to add the contents of %rax and %rdi - the instruction for this is
addq %rax, %rdi
What this does is take the value in %rax, add it to the value in %rdi, and store the resulting value in %rdi, erasing whatever was there before - the two operands are still usually considered the “source” and the “destination” even though they both are used as sources of the value p35 - arithmetic.s p40 - binaryexit.s
movq $0b1101, %rdi # 1101 = 13 --- 11101 = 16 + 13 = 29
movq $60, %rax
ch1 - Introduction
Welcome to Programming p1 - love programming, make working progr. with style - like poetry - own world own rules - ... Knuth - most introduct. books frustrate - goal is from knowing nothing about programming to understand how to think, write, and learn like a peogrammer - will not learn everything, but will have background for how everything fits together - end of book be able doing: p2 - • understand how program works and interacts with other programs
• Read other people’s programs and learn how they work
• Learn new programming languages quickly
• Learn advanced concepts in computer science quickly
will teach not everything, but foundations to go wherever you want afterwards - must be patient learning - not understand, read, come back to it later - end of each chapter 3 sets of review exercises exc, 1st regurgitation, give back what you learned in ch - 2nd application questions, check if you can apply what learned - 3rd if capable broadening your horizon, maybe some only later answerable, but can think about - other questions require research, other require to analyze options - many not right or wrong answers ... p3 -
- problems -> mailing list firstname.lastname@example.org or subscribe mail.nongnu.org Your Tools - book teaches assembly language for x86 processors and GNU/Linux operating system - (check your system: $ hostnamectl -> FO output: Architecture: x86-64) - all examples given using GNU/Linux standard GCC tool set - will be described shortly - if new to Linux check out the guide available at http://rute.sourceforge.net/1 What I intend to show you is more about programming in general than using a specific tool set on a specific platform, but standardizing on one makes the task much easier
Those new to Linux should also try to get involved in their local GNU/Linux User’s Group - User’s Group members are usually very helpful for new people, and will help you from everything from installing Linux to learning to use it most efficiently - listing of GNU/Linux User’s Groups is available at
linux.org/groups - all of these programs have been tested using Red Hat Linux 8.0, and should work with any other GNU/Linux distribution, too.2 - they will not work with non-Linux operating systems such as BSD or other systems - however, all of the skills learned in this book should be easily transferable to any other system
If you do not have access to a GNU/Linux machine, you can look for a hosting provider who offers a Linux shell account, which is a command-line only interface ...
... p5 - ... - There are essentially three kinds of languages:
• Machine Language
This is what the computer actually sees and deals with - every command the computer sees is given as a number or sequence of numbers p6 -
• Assembly Language
This is the same as machine language, except the command numbers have been replaced by letter sequences which are easier to memorize - other small things are done to make it easier as well
• High-Level Language
High-level languages are there to make programming easier - assembly language requires you to work with the machine itself - High-level languages allow you to describe the program in a more natural language - a single command in a high-level language usually is equivalent to several commands in an assembly language
In this book we will learn assembly language, although we will cover a bit of high-level languages. Hopefully by learning assembly language, your understanding of how programming and computers work will put you a step ahead
ch2 - Computer Architecture p7 - before learning programming need first understand how computer interprets programs + some basics - modern computer architecture is based off of Von Neumann architecture, named after creator - divides computer up into 2 main parts - CPU (for Central Processing Unit) and the memory - this architecture used in all modern computers, including personal computers, supercomputers, mainframes, and even cell phones Structure of Computer Memory
To understand how the computer views memory, imagine your local post office. They usually have a room filled with PO Boxes. These boxes are similar to computer memory in that each are numbered sequences of fixed-size storage locations. For example, if you have 256 megabytes of computer memory, that means that your computer contains roughly 256 million fixed-size storage locations. Or, to use our analogy, 256 million PO Boxes. Each location has a number, and each location has the same, fixed-length size. The difference between a PO Box and computer memory is that you can store all different kinds of things in a PO Box, but you can only store a single number in a computer memory storage location
... p9 - ... - computer data + programs live in memory, both stored and accessed in same way The CPU
not only storing data, but need to be able to access, manipulate, move it - CPU does this, reads in instructions from memory one at a time and executes them, known as fetch-execute cycle - elements of CPU:
•Arithmetic and logic unit program counter is used to tell computer where to fetch the next instruction from, and holds the memory address of the next instruction to be executed - the CPU begins by looking at the program counter, and fetching whatever number is stored in memory at the location specified. It is then passed on to the instruction p10 - decoder which figures out what the instruction means. This includes what process needs to take place (addition, subtraction, multiplication, data movement, etc.) and what memory locations are going to be involved in this process. Computer instructions usually consist of both the actual instruction and the list of memory locations that are used to carry it out.
Now the computer uses the data bus to fetch the memory locations to be used in the calculation. The data bus is the connection between the CPU and memory. It is the actual wire that connects them. If you look at the motherboard of the computer, the wires that go out from the memory are your data bus.
In addition to the memory on the outside of the processor, the processor itself has some special, high-speed memory locations called registers. There are two kinds of registers - general registers and special-purpose registers. General-purpose registers are where the main action happens. Addition, subtraction, multiplication, comparisions, and other operations generally use general-purpose registers for processing. However, computers have very few general-purpose registers. Most
information is stored in main memory, brought in to the registers for processing, and then put back into memory when the processing is completed. special-purpose registers are registers which have very specific purposes. We will discuss these as we come to them.
Now that the CPU has retrieved all of the data it needs, it passes on the data and the decoded instruction to the arithmetic and logic unit for further processing. Here the instruction is actually executed. After the results of the computation have been calculated, the results are then placed on the data bus and sent to the appropriate location in memory or in a register, as specified by the instruction.
This is a very simplified explanation. Processors have advanced quite a bit in recent years, and are now much more complex. Although the basic operation is still the same, it is complicated by the use of cache hierarchies, superscalar processors, pipelining, branch prediction, out-of-order execution, microcode translation, coprocessors, and other optimizations. Don’t worry if you don’t know what those words mean, you can just use them as Internet search terms if you want to learn more about the CPU. p11 - Some Terms
... p12 - ... - computer can’t tell difference between a value that is an address, a value that is a number, a value that is an ASCII code, or a value that you have decided to use for another purpose - a number becomes an ASCII code when you attempt to display it - a number becomes an address when you try to
look up the byte it points to - take a moment to think about this, because it is crucial to understanding how computer programs work Addresses which are stored in memory are also called pointers, because instead of having a regular value in them, they point you to a different location in memory
As we’ve mentioned, computer instructions are also stored in memory. In fact, p13 - they are stored exactly the same way that other data is stored. The only way the computer knows that a memory location is an instruction is that a special-purpose
register called the instruction pointer points to them at one point or another. If the instruction pointer points to a memory word, it is loaded as an instruction. Other than that, the computer has no way of knowing the difference between programs and other types of data.2 Interpreting Memory
Computers are very exact - because they are exact, programmers have to be equally exact - ...
... p15 - Data Accessing Methods
Processors have a number of different ways of accessing data, known as addressing modes - the simplest mode is immediate mode, in which the data to access is embedded in the instruction itself - for example, if we want to initialize a register to
0, instead of giving the computer an address to read the 0 from, we would specify immediate mode, and give it the number 0
In the register addressing mode, the instruction contains a register to access, rather than a memory location - the rest of the modes will deal with addresses
In the direct addressing mode, the instruction contains the memory address to access - for example, I could say, please load this register with the data at address 2002 - the computer would go directly to byte number 2002 and copy the contents into our register
In the indexed addressing mode, the instruction contains a memory address to access, and also specifies an index register to offset that address - for example, we could specify address 2002 and an index register - if the index register contains the number 4, the actual address the data is loaded from would be
2006 - this way, if you have a set of numbers starting at location 2002, you can cycle between each of them using an index register - on x86 processors, you can also specify a multiplier for the index - this allows you to access memory a
byte at a time or a word at a time (4 bytes) - if you are accessing an entire word, your index will need to be multiplied by 4 to get the exact location of the fourth element from your address - for example, if you wanted to access the fourth byte from location 2002, you would load your index register with 3
(remember, we start counting at 0) and set the multiplier to 1 since you are going a byte at a time - this would get you location 2005 - however, if you wanted to access the fourth word from location 2002, you would load your index register with 3 and set the
multiplier to 4 - this would load from location 2014 - the fourth word - take the time to calculate these yourself to make sure you understand how it works
In the indirect addressing mode, the instruction contains a register that contains a pointer to where the data should be accessed - for example, if we used indirect p16 - addressing mode and specified the %eax register, and the %eax register contained the value 4, whatever value was at memory location 4 would be used - in direct addressing, we would just
load the value 4, but in indirect addressing, we use 4 as the address to use to find the data we want
Finally, there is the base pointer addressing mode - this is similar to indirect addressing, but you also include a number called the offset to add to the register’s value before using it for lookup - we will use this mode quite a bit in this book
In the Section called Interpreting Memory we discussed having a structure in memory holding customer information - let’s say we wanted to access the customer’s age, which was the eighth byte of the data, and we had the address of the
start of the structure in a register - we could use base pointer addressing and specify the register as the base pointer, and 8 as our offset - this is a lot like indexed addressing, with the
difference that the offset is constant and the pointer is held in a register, and in indexed addressing the offset is in a
register and the pointer is constant
There are other forms of addressing, but these are the most important ones Review Know the Concepts
• Describe the fetch-execute cycle
• What is a register? How would computation be more difficult without registers?
• How do you represent numbers larger than 255?
• How big are the registers on the machines we will be using?
• How does a computer know how to interpret a given byte or set of bytes of memory? p17 - • What are the addressing modes and what are they used for?
• What does the instruction pointer do? Use the Concepts
• What data would you use in an employee record? How would you lay it out in memory?
• If I had the pointer the the beginning of the employee record above, and wanted to access a particular piece of data inside of it, what addressing mode would I use?
• In base pointer addressing mode, if you have a register holding the value 3122, and an offset of 20, what address would you be trying to access?
• In indexed addressing mode, if the base address is 6512, the index register has a 5, and the multiplier is 4, what address would you be trying to access?
• In indexed addressing mode, if the base address is 123472, the index register has a 0, and the multiplier is 4, what address would you be trying to access?
• In indexed addressing mode, if the base address is 9123478, the index register has a 20, and the multiplier is 1, what address would you be trying to access? Going Further
• What are the minimum number of addressing modes needed for computation?
• Why include addressing modes that aren’t strictly needed?
• Research and then describe how pipelining (or one of the other complicating factors) affects the fetch-execute cycle p18 - • Research and then describe the tradeoffs between fixed-length instructions and variable-length instructions
ch3 - Your First Programs
... p19 - tinker around with these programs - create exit.s - section called Outline of an Assembly Language Program (p22) will describe how it works p20 - this is called source code, the human-readable form of a program p21 - to transform it into a program that a computer can run, need to assemble and link it: $ as exit.s -o exit.o # assembles itas = command which runs assembler - exit.s is source file - -o exit.o = tells to put output in file exit.o, which is an object file (code in machine's language, not been completely put together) - most large programs have several source files, each must be converted into an object file - linker = program responsible putting object files together and adding information to it that kernel knows how to load and run it - in our case only one object file, so linker only adding info to enable it to run - to link the file, enter command
$ ld exit.o -o exit # links itld = command to run linker, exit.o is the object file we want to link, and -o exit instructs linker to output the new program into a file called exit1 - if any of these commands reported errors, you have either mistyped your program or the command - after correcting the program, you have to re-run all the commands. You must always
re-assemble and re-link programs after you modify the source file for the changes to occur in the program - you can run exit by typing in the command
$ ./exit # runs exit - jumps to next line
$ echo s? 0 # output --- # = comment./ used to tell computer that program is in the current directory - only thing that happens is that you’ll go to the next line
files in Linux don’t have to have extensions, while Windows® uses .exe extension to signify an executable program - UNIX executables usually have no extension p22 - because program does nothing but exit - after running program, type in echo $? it will say 0 - every program when it exits gives Linux an exit status code, which tells it if everything went all right - if so, it returns0 - UNIX programs return numbers other than zero to indicate failure or other errors, warnings, or statuses - the programmer determines what each number means - you can view this code by typing in echo $? - in following section we will look at what each part of the code does Outline of an Assembly Language Program
program we just entered: at beginning lots of lines begin with hashes (#) = comments, not translated by assembler - only for programmer to anyone who looks at code in future - most programs you write will be modified by others - develop habit writing comments that will help them understand both why program exists and how it works - always include following:
• purpose of the code
• an overview of the processing involved
• anything strange your program does and why it does it3
After comments next line says .section .data
3. many programs end up doing things strange ways - usually reason for that, but, unfortunately, programmers never document such things in their comments - future programmers either have to learn reason the hard way modifying code watching it break, or just leaving it alone whether it is still needed or not - always document any strange behavior your program performs - figuring out what is strange and what is straightforward comes mostly with experience p23 - Anything starting with a period. isn’t directly translated into a machine instruction - it’s an instruction to the assembler itself, called assembler directives or pseudo-operations because they are handled by the assembler and are not actually run by the computer - the .section command breaks program up into sections and
starts the data section, where you list any memory storage you will need for data - our program doesn’t use any, so we don’t need the section - it’s just here for completeness - almost every program you write in the future will have data
Right after this you have .section .text
which starts the text section - the text section of a program is where the program instructions live
The next instruction is .globl _start
- this instructs the assembler that _start is important to remember - _start is a symbol, which means that it is going to be replaced by something else either during assembly or linking - symbols are generally used to mark locations of programs or data, so you can
refer to them by name instead of by their location number - imagine if you had to refer to every memory location by it’s address - first of all, it would be very confusing because you would have to memorize or look up the numeric memory address of every piece of code or data - in addition, every time you had to insert a piece of data or code you would have to change all the addresses in your program! - symbols are used so that the assembler and linker can take care of keeping track of addresses, and you can concentrate on writing your program p24 - .globl means that the assembler shouldn’t discard (verwerfen) this symbol after assembly, because the linker will need it - _start is a special symbol that always needs to be marked with .globl because it marks the
location of the start of the program Without marking this location in this way, when the computer loads your program it won’t know where to begin running your program
The next line _start:
defines the value of the _start label - a label is a symbol followed by a colon: - labels define a symbol’s value - when assembler is assembling the program, it has to assign each data value and instruction an address - labels tell the assembler to make the symbol’s value be wherever the next instruction or data element will be - this way, if the actual physical location of the data or instruction changes, you don’t have to rewrite any references to it - the symbol
automatically gets the new value
Now we get into actual computer instructions - the first such instruction is this: movl $1, %eax
When the program runs, this instruction transfers the number 1 into the %eax register - in assembly language, many instructions have operands - movl has two operands - the source and the destination - in this case, the source is the literal number 1, and the
destination is the %eax register - operands can be numbers, memory location references, or registers - different instructions allow different types of operands - see
Appendix B for more information on which instructions take which kinds of operands
On most instructions which have two operands, the first one is the source operand and the second one is the destination - note that in these cases, the source operand is not modified at all - other instructions of this type are, for example, addl,
subl, and imull - these add/subtract/multiply the source operand from/to/by the destination operand and andsave the result in the destination operand -
other p25 - instructions may have an operand hardcoded in - idivl, for example, requires that the dividend be in %eax, and %edx be zero, and the
quotient is then transferred to %eax and the remainder to %edx - however, the divisor can be any register or memory location
On x86 processors, there are several general-purpose registers4 (all of which can be used with movl):
In addition to these general-purpose registers, there are also several special-purpose registers, including:
We’ll discuss these later, just be aware that they exist5 - some of these registers,
4. Note that on x86 processors, even the general-purpose registers have some special purposes, or used to before it went 32-bit - however, these are general-purpose registers for most instructions - each of them has at least one instruction where it is used in a special way - however, for most of them, those instructions aren’t covered in this book
5. You may be wondering, why do all of these registers begin with the letter e? - the reason is that early generations of x86 processors were 16 bits rather than 32 bits - therefore, the registers were only half the length they are now - in later generations of x86 processors, the size of the registers doubled - they kept the old names to refer to the first half of the register, p26 - like %eip and %eflags can only be accessed through special instructions - the others can be accessed using the same instructions as general-purpose registers, but they have special meanings, special
uses, or are simply faster when used in a specific way
So, the movl instruction moves the number 1 into %eax - the dollar-sign $ in front of the one 1 indicates that we want to use immediate mode addressing (refer back to the Section called Data Accessing Methods in Chapter 2) - without the dollar-sign it would do direct addressing, loading whatever number is at address1 - we want the actual number1 loaded in, so we have to use immediate mode
The reason we are moving the number 1 into %eax is because we are preparing to call the Linux Kernel - the number 1 is the number of the exit system call - we will discuss system calls in more depth soon, but basically they are requests for the operating system’s help - normal
programs can’t do everything - many operations such as calling other programs, dealing with files, and exiting have to be handled by the operating system through system calls - when you make a system call, which we will do shortly, the system call number has to be loaded into
%eax (for a complete listing of system calls and their numbers, see Appendix C) - depending on the system call, other registers may have to have values in them as well - note that system calls is not the only use or even the main use of registers - it is just the one we are dealing with in this first program - later programs will use registers for
The operating system, however, usually needs more information than just which call to make - for example, when dealing with files, the operating system needs to know which file you are dealing with, what data you want to write, and other details - the extra details, called parameters are stored in other registers - in the case of the exit system call, the operating system requires a
status code be loaded
and added an e to refer to the extended versions of the register - usually you will only use the extended versions - newer models also offer a 64-bit mode, which doubles the size of these registers yet again and uses an
rprefix to indicate the larger registers (i.e. %rax is the 64-bit version of %eax) - however, these processors are not widely used, and are not covered in this book p27 - in %ebx - this value is then returned to the system - this is the value you retrieved when you typed echo $? - so, we load %ebx with 0 by typing the following: movl $0, %ebx
Now, loading registers with these numbers doesn’t do anything itself. Registers are used for all sorts of things besides system calls. They are where all program logic such as addition, subtraction, and comparisons take place. Linux simply requires that certain registers be loaded with certain parameter values before making a system call. %eax is always required to be loaded with the system call number. For the other registers, however, each system call has different requirements. In the exit system call, %ebx is required to be loaded with the exit status. We will
discuss different system calls as they are needed. For a list of common system calls and what is required to be in each register, see Appendix C
The next instruction is the "magic" one. It looks like this: int $0x80
The int stands for interrupt. The 0x80 is the interrupt number to use.6 - an interrupt interrupts the normal program flow, and transfers control from our program to Linux so that it will do a system call.7. You can think of it as like signaling Batman(or Larry-Boy8, if you prefer). You need something done, you send the signal, and then he comes to the rescue. You don’t care how he does his work - it’s more or less magic - and when he’s done you’re back in control. In this case, all we’re doing is asking Linux to terminate the program, in which case we
6. You may be wondering why it’s 0x80 instead of just 80. The reason is that the number is written in hexadecimal. In hexadecimal, a single digit can hold 16 values instead of the normal 10. This is done by utilizing the letters a through f in addition to the regular digits. a represents 10, b represents 11, and so on. 0x10 represents the number 16, and so on. This will be discussed more in depth later, but just be aware that numbers starting with 0x are in hexadecimal. Tacking on an H at the end is also sometimes used instead, but we won’t do that in this book. For more information about this, see Chapter 10
7. Actually, the interrupt transfers control to whoever set up an interrupt handler for the interrupt number. In the case of Linux, all of them are set to be handled by the Linux kernel
8. If you don’t watch Veggie Tales, you should - start with Dave and the Giant Pickle p28 - won’t be back in control. If we didn’t signal the interrupt, then no system call would have been performed.
Quick System Call Review: To recap - Operating System features are accessed through system calls. These are invoked by setting up the registers in a special way and issuing the instruction int $0x80. Linux knows which system call we want to access by what we stored in the %eax register. Each system call has other requirements as to what needs to be stored in the other registers. System call number 1 is the exit system call, which requires the status code to be placed in %ebx.
Now that you’ve assembled, linked, run, and examined the program, you should make some basic edits. Do things like change the number that is loaded into %ebx, and watch it come out at the end with echo $?. Don’t forget to assemble and link it again before running it. Add some comments. Don’t worry, the worse thing that would happen is that the program won’t assemble or link, or will freeze your screen. That’s just part of learning! Planning the program
In our next program we will try to find the maximum of a list of numbers. Computers are very detail-oriented, so in order to write the program we will have to have planned out a number of details. These details include:
• Where will the original list of numbers be stored?
• What procedure will we need to follow to find the maximum number?
• How much storage do we need to carry out that procedure?
• Will all of the storage fit into registers, or do we need to use some memory as well? p29 - You might not think that something as simple as finding the maximum number from a list would take much planning. You can usually tell people to find the
maximum number, and they can do so with little trouble. However, our minds are used to putting together complex tasks automatically. Computers need to be instructed through the process. In addition, we can usually hold any number of things in our mind without much trouble. We usually don’t even realize we are doing it. For example, if you scan a list of numbers for the maximum, you will
probably keep in mind both the highest number you’ve seen so far, and where you
are in the list. While your mind does this automatically, with computers you have
to explicitly set up storage for holding the current position on the list and the
current maximum number. You also have other problems such as how to know
when to stop. When reading a piece of paper, you can stop when you run out of
numbers. However, the computer only contains numbers, so it has no idea when it
has reached the last of your numbers.
In computers, you have to plan every step of the way. So, let’s do a little planning.
First of all, just for reference, let’s name the address where the list of numbers
starts as data_items. Let’s say that the last number in the list will be a zero, so
we know where to stop. We also need a value to hold the current position in the
list, a value to hold the current list element being examined, and the current
highest value on the list. Let’s assign each of these a register:
• %ediwill hold the current position in the list.
• %ebxwill hold the current highest value in the list.
• %eaxwill hold the current element being examined.
When we begin the program and look at the first item in the list, since we haven’t
seen any other items, that item will automatically be the current largest element in
the list. Also, we will set the current position in the list to be zero - the first
element. From then, we will follow the following steps: p30 - 1. Check the current list element (%eax) to see if it’s zero (the terminating element).
2. If it is zero, exit.
3. Increase the current position (%edi).
4. Load the next value in the list into the current value register (%eax). What addressing mode might we use here? Why?
5. Compare the current value (%eax) with the current highest value (%ebx).
6. If the current value is greater than the current highest value, replace the current highest value with the current value.
That is the procedure. Many times in that procedure I made use of the word "if".
These places are where decisions are to be made. You see, the computer doesn’t
follow the exact same sequence of instructions every time. Depending on which
"if"s are correct, the computer may follow a different set of instructions. The
second time through, it might not have the highest value. In that case, it will skip
step 6, but come back to step 7. In every case except the last one, it will skip step
2. In more complicated programs, the skipping around increases dramatically.
These "if"s are a class of instructions called flow control instructions, because they
tell the compute which steps to follow and which paths to take. In the previous
program, we did not have any flow control instructions, as there was only one
possible path to take - exit. This program is much more dynamic in that it is
directed by data. Depending on what data it receives, it will follow different
In this program, this will be accomplished by two different instructions, the
conditional jump and the unconditional jump. The conditional jump changes paths
based on the results of a previous comparison or calculation. The unconditional
jump just goes directly to a different path no matter what. The unconditional jump
may seem useless, but it is very necessary since all of the instructions will be laid p31 - out on a line. If a path needs to converge back to the main path, it will have to do
this by an unconditional jump. We will see more of both of these jumps in the next
Another use of flow control is in implementing loops. A loop is a piece of program
code that is meant to be repeated. In our example, the first part of the program
(setting the current position to 0 and loading the current highest value with the
current value) was only done once, so it wasn’t a loop. However, the next part is
repeated over and over again for every number in the list. It is only left when we
have come to the last element, indicated by a zero. This is called a loop because it
occurs over and over again. It is implemented by doing unconditional jumps to the
beginning of the loop at the end of the loop, which causes it to start over. However,
you have to always remember to have a conditional jump to exit the loop
somewhere, or the loop will continue forever! This condition is called an infinite
loop. If we accidentally left out step 1, 2, or 3, the loop (and our program) would
In the next section, we will implement this program that we have planned.
Program planning sounds complicated - and it is, to some degree. When you first
start programming, it’s often hard to convert our normal thought process into a
procedure that the computer can understand. We often forget the number of
"temporary storage locations" that our minds are using to process problems. As
you read and write programs, however, this will eventually become very natural to
you. Just have patience. Finding a Maximum Value
Enter the following program as maximum.s: maximum.s
ch4 - All About Functions Dealing with Compexity p49 - ...
ch11 - High-Level Languages p213 - ...
p215 - C - The Development of the C Language - create helloworld.c
/* PURPOSE: This program is mean to show a basic */
/* C program. All it does is print */
/* "Hello World!" to the screen and */
/* exit. */
/* Main Program */
int main(int argc, char **argv)
/* Print our string to standard output */
/* Exit with status 0 */
return 0; }
Compile it: $ gcc -o HelloWorld Hello-World.c
Run helloworld in terminal - $ ./helloworld
p218 - Perl - perl.org - create helloworld.pl
Run helloworld in terminal - $ perl helloworld.pl
p219 - Python - python.org - create helloworld.py #!/usr/bin/python
print "Hello World!"
Run helloworld in terminal - $ python helloworld.py
ch12 - Optimization p223 - ...
ch13 - Moving On from Here p233 - Even if you never use assembly language again, you have gained a valuable perspective and mental framework for understanding the rest of computer science Three methods to learn: bottom-up - top-down - from the middle - good programmer takes all of them into account
p234 - Recommended books
p237 - Further Recources on Assembly Language - http://linuxassembly.org :-) and many more - p239 Appendix A-I - p313 Index - p319 end of book
Assembly Language Programming with Ubuntu
download book by Ed Jorgensen, Ph.D. - Version 1.1.40 January 2020 - 20ch 314p
ch1 - Hello, world of assembly language
quick-start - start writing assembly language programs as rapidly as possible
• Presents the basic syntax of an HLA (High Level Assembly) program
• Introduces you to the Intel CPU architecture
• Provides a handful of data declarations, machine instructions, and high-level control statements
• Describes some utility routines you can call in the HLA Standard Library
• Shows you how to write some simple assembly language programs
By the conclusion of this chapter, you should understand the basic syntax of an HLA program and should understand the prerequisites that are needed to start learning new assembly language features in the chapters that follow.
1.1 - The Anatomy of an HLA Program
Figure 1-1 - program pgmID - << Declarations >> - begin pgmID; - << Statements >> - end pgmID;
msg: db "Hello, world! >>> from Assembly :-)", 10
.len: equ $ - msg
Compile helloworld.asm in terminal: $ nasm -f macho64 -O0 helloworld.asm - (before you must have nasm installed, via brew, gcc or Xcode etc. - test: $ nasm -v - output: NASM version 2.13.02 compiled on Nov 30 2017)
This will produce a helloworld.o (object) file. You then need to finish this by linking: $ ld helloworld.o -o helloworld
You can now run with $ ./helloworld - the output should be: Hello, world! >>> from Assembly :-)