Peer to Peer Journal Articles
Literature Review
Chapter 1: Assembly Language’s Index /Offset
There is no such thing Geometrically as a Perfect Line, Circle, or Rectangle nor Triangle
Core of creating Data to place hold and geometrically “ “ perfect the Table or “ “. Opens the Research Topic of Indexing in Assembly Language:
Using an index register to process an array To process an array in a loop, we can put the offset into a register. The register we use to hold an offset is called an index register. Traditionally the registers used for this purpose are esi or edi. The ‘I’ stands for “index.” To initialize an index register, zero it out: sub esi,esi ; index register Then use the register in place of the constant: add eax,[arr+esi].
This line of code can be reused in a loop by changing the value of esi:
To process an array using an index register, start with initializing a loop counter: to do that, put the number of values in the array into ecx.
Also, the index register to 0. In the loop, increment the index register by the size of each array element, which is 4 for a doubleword. In this example, we’ll sum the 4 values in the arr array; that means we must also set sum (eax) to 0 and add each array value into eax:
mov ecx, 3 ; l
oop counter sub esi,esi ;
index register sub eax,eax ; sum = 0
top: add eax,[arr+esi]
add esi,4 ; increment index loop top Using a base register to process an array Another way to process an array is to use a base register.
While the index register holds the offset of the array from the beginning of the array, the base register holds the address of the array from the beginning of the data segment: Suppose the data segment looks like the following (the left column is the offset of each item from the beginning of the data segment, measured in bytes). .data 0000 x dword 10 0004 arr dword 5, 7, 19 0010 n dword 3 If we were to list all the elements individually, the address of each element would be clearer: .data 0000 x dword 10 0004 arr dword 5 0008 dword 7 000C dword 19 0010 n dword 3 arr +0 +4 +8 <– index register contents 5 7 19 0004 0008 000C <– base register contents
Description
To process an array using a base register, you must put the address of the first element of the array into a base register. Traditionally the base register is ebx. The instruction to put the address of an array into a register is lea, or load effective address: lea ebx,arr Using the example above, this puts 0004 into ebx. Base register notation is the following: [ebx] To move the first value from the array into eax, write the following: mov eax,[ebx] To change to the next value in the array, increment ebx by the size of each array element; in an array of dwords, this is 4: add ebx,4 To process an array using a base register, start with initializing a loop counter Also initialize the index register to 0. In the loop, increment the base register by the size of each array element, which is 4 for a doubleword: To process an array using a base register, start by initializing a loop counter. Also initialize the base register to the initial address of the array. In the loop, increment the base register by the size of each array element, which is 4 for a doubleword. In this example, we’ll sum the 4 values in the arr array; that means we must also set
sum (eax) to 0 and
add each array value
into eax: mov ecx,3 ;
loop counter lea ebx, arr ;
base register sub eax,eax ;
sum = 0 top:
add eax,[ebx]
add ebx,4 ; increment base register loop top
Passing an array as a parameter Between index register and base register notation, index register notation is clearer and easier to read. However, it is necessary to use base register notation when sending an array as a parameter to a procedure. A procedure can’t refer to any variables declared in main, and the array is declared in main.
.data 0000 x dword 10 0004
arr dword 5, 7, 19 0010
n dword 4
To send an array as a parameter to a procedure, you must pass the base address of the array. It is most efficient to pass the address in ebx. In addition, you must pass the number of filled positions in the array; this is not passed by address or reference, but by value: you put the value of n into a register. It is most efficient to put that value into ecx, which Is where it will be used. To pass an array arr and n as parameters to the function addup, do the following. The function will return the sum in eax: lea ebx,arr mov ecx,n call addup mov sum,eax ; store return value Inside the function, you can begin to process the array directly using base address notation, since the address is already in ebx, and the loop counter is already in ecx. addup proc sub eax, eax ; sum = 0 addtop: add eax,[ebx] add ebx,4 loop addtop ret addup endp What’s wrong with this? We haven’t pushed and popped registers that are changed but that are not used to return a value. Those would be ebx and ecx, so we modify the code as follows: addup proc push ebx push ecx sub eax, eax ; sum = 0 addtop: add eax,[ebx] add ebx,4 loop addtop pop ecx pop ebx ret addup endp
With the .OFFSET directive you tell the assembler to give the location counter a new offset relative to the start of the section.
When the assembler encounters the .OFFSET directive, it moves the location counter forwards to the specified address, relative to the start of the section, and places the next instruction on that address. If you specify an address equal to or lower than the current position of the location counter, the assembler issues an error.
A label is not allowed with this directive.
Example
.SECTION .text
nop
nop
nop
.OFFSET 0x20 ; the assembler places
nop ; this instruction at address 0x20
; relative to the start of the section.
.ENDSEC
.SECTION .text
nop
nop
nop
.OFFSET 0x02 ; WRONG: the current position of the
nop ; location counter is 0x0C.
.ENDSEC
The main tools to write programs in x86 assembly are the processor registers. The registers are like variables built in the processor. Using registers instead of memory to store values makes the process faster and cleaner. The problem with the x86 serie of processors is that there are few registers to use. This section describes the main use of each register and ways to use them. That in note that the rules described here are more suggestions than strict rules. Some operations need absolutely some kind of registers but most of the you can use any of the freely.
Here is a list of the available registers on the 386 and higher processors. This list shows the 32 bit registers. Most of the can be broken down to 16 or even 8 bits register.
General registers
EAX EBX ECX EDX
Segment registers
CS DS ES FS GS SS
Index and pointers
ESI EDI EBP EIP ESP
Indicator
EFLAGS
General registers
As the title says, general register are the one we use most of the time Most of the instructions perform on these registers. They all can be broken down into 16 and 8 bit registers.
32 bits : EAX EBX ECX EDX
16 bits : AX BX CX DX
8 bits : AH AL BH BL CH CL DH DL
The “H” and “L” suffix on the 8 bit registers stand for high byte and low byte. With this out of the way, let’s see their individual main use
EAX,AX,AH,AL : Called the Accumulator register.
It is used for I/O port access, arithmetic, interrupt calls,
etc…
EBX,BX,BH,BL : Called the Base register
It is used as a base pointer for memory access
Gets some interrupt return values
ECX,CX,CH,CL : Called the Counter register
It is used as a loop counter and for shifts
Gets some interrupt values
EDX,DX,DH,DL : Called the Data register
It is used for I/O port access, arithmetic, some interrupt
calls.
Segment registers
Segment registers hold the segment address of various items. They are only available in 16 values. They can only be set by a general register or special instructions. Some of them are critical for the good execution of the program and you might want to consider playing with them when you’ll be ready for multi-segment programming
CS : Holds the Code segment in which your program runs.
Changing its value might make the computer hang.
DS : Holds the Data segment that your program accesses.
Changing its value might give erronous data.
ES,FS,GS : These are extra segment registers available for
far pointer addressing like video memory and such.
SS : Holds the Stack segment your program uses.
Sometimes has the same value as DS.
Changing its value can give unpredictable results,
mostly data related.
Indexes and pointers
Indexes and pointer and the offset part of and address. They have various uses but each register has a specific function. They some time used with a segment register to point to far address (in a 1Mb range). The register with an “E” prefix can only be used in protected mode.
ES:EDI EDI DI : Destination index register
Used for string, memory array copying and setting and
for far pointer addressing with ES
DS:ESI EDI SI : Source index register
Used for string and memory array copying
SS:EBP EBP BP : Stack Base pointer register
Holds the base address of the stack
SS:ESP ESP SP : Stack pointer register
Holds the top address of the stack
CS:EIP EIP IP : Index Pointer
Holds the offset of the next instruction
It can only be read
The EFLAGS register
The EFLAGS register hold the state of the processor. It is modified by many intructions and is used for comparing some parameters, conditional loops and conditionnal jumps. Each bit holds the state of specific parameter of the last instruction. Here is a listing :
Bit Label Desciption
—————————
0 CF Carry flag
2 PF Parity flag
4 AF Auxiliary carry flag
6 ZF Zero flag
7 SF Sign flag
8 TF Trap flag
9 IF Interrupt enable flag
10 DF Direction flag
11 OF Overflow flag
12-13 IOPL I/O Priviledge level
14 NT Nested task flag
16 RF Resume flag
17 VM Virtual 8086 mode flag
18 AC Alignment check flag (486+)
19 VIF Virutal interrupt flag
20 VIP Virtual interrupt pending flag
21 ID ID flag
Those that are not listed are reserved by Intel.
Undocumented registers
There are registers on the 80386 and higher processors that are not well documented by Intel. These are divided in control registers, debug registers, test registers and protected mode segmentation registers. As far as I know, the control registers, along with the segmentation registers, are used in protected mode programming, all of these registers are available on 80386 and higher processors except the test registers that have been removed on the pentium. Control registers are CR0 to CR4, Debug registers are DR0 to DR7, test registers are TR3 to TR7 and the protected mode segmentation registers are GDTR (Global Descriptor Table Register), IDTR (Interrupt Descriptor Table Register), LDTR (Local DTR), and TR.
Bottom of Form