Monday 14 November 2011

Low Level Assembly Stuffs

Low Level Assembly Stuffs


x86 Interrupts

Whenever external devices trigger the interrupt line, the CPU will notice the change of status in interrupt line, and update the interrupt status register. The CPU will then store the state info on the stack (for returning to current activities later), inspect the interrupt descriptor table (IDT), and jump to location pointed to by the IDT. The OS takes over from there. Subsequently, user-defined interrupt handler will be executed.

IDT is a data structure used by the x86 architecture in determining the correct response to interrupts and exceptions. IDT is setup by the OS, and can be anywhere in the memory. Use of the IDT can be triggered by three types of events: hardware interrupts, software interrupts and exceptions. In total, up to 256 of these can be defined, each with their own unique identifier which is called a descriptor. The IDT is an array of these 8-byte descriptors stored consecutively in memory and indexed by the interrupt vector. Vectors 0-15 are for processor generated exceptions (general protection fault, page fault, etc.). Vectors 16-31 are typically used for hardware interrupts, and higher vector numbers are only generated by software.


GNU Assembler Directives


All assembler directives have names that begin with a period (.). The rest of the name is made of letters, usually in lower case.

Local Symbol Names


.macro    mvRocClkDelay  clk, reg=r0, tmp=r1
 ldr     \reg, =\clk
 ldr     \tmp, =CNTMR_RELOAD_REG(0)
 str     \tmp, [\tmp]
1:    
 ldr     \tmp, [\tmp]
 cmp     \tmp, #0
 bne     1b
.endm

bne  1b  - b is backwards,  1: is  local label 

Macro


.macro mvMovReg mode=CPSR_MBIT_FIQ, orgmode=CPSR_MBIT_SVC, reg=r0, regno=14, dir=0
 msr  cpsr_c, #\mode
 .if (\dir==0)
 mov  r\regno, \reg
 .else
 mov  \reg, r\regno
 .endif
 msr  cpsr_c, #\orgmode 
.endm

mode, orgmode, etc are macro parameters
\reg refers to parameter within macro
mode=CPSR_MBIT_FIQ, etc are default parameters

Special Dot Symbol

It assigns a value to ".", it is the same as a .org directive.

__asm__ __volatile__ (  
     "ldr  %1, .+8  \n" 
     "b  .+12  \n" 
     ".long  0  \n" 
     ".long  .+12  \n" 
     "ldr  %0, .-4  \n"    
     "sub  %0, pc, %0  \n" 
     "add  %0, %0, %1 \n" 
        :"=r"(tmp), "=r"(tmp1)
        );
        
b .+12 will jump to ldr %0, .-4
ldr %1, .+8 will load from the location of .long 0
.long .+12 will assign the address value of  "add %0, %0, %1\n" to 
current location 

AT&T Syntax versus Intel Syntax

The x86 assembly language has two main syntax branches: Intel syntax, originally used for documentation of the x86 platform, and AT&T syntax. Intel syntax is dominant in the Windows world, and AT&T syntax is dominant in the Unix world,

Furthermore, AT&T System V/386 assembler syntax is quite different from Intel syntax. Major differences between the two syntaxes are:

AT&T immediate operands are preceded by `$'; Intel immediate operands are un-delimited (Intel `push 4' is AT&T `pushl $4'). AT&T register operands are preceded by `%'; Intel register operands are un-delimited. AT&T absolute (as opposed to PC relative) jump/call operands are prefixed by `*'; they are un-delimited in Intel syntax.

AT&T and Intel syntax use the opposite order for source and destination operands. Intel is `add eax, 4'. AT&T is is `addl $4, %eax'.

In AT&T syntax the size of memory operands is determined from the last character of the instruction mnemonic. Mnemonic suffixes of `b', `w', `l' and `q' specify byte (8-bit), word (16-bit), long (32-bit) and quadruple word (64-bit) memory references. Intel syntax accomplishes this by prefixing memory operands (_not_ the instruction mnemonics) with `byte ptr', `word ptr', `dword ptr' and `qword ptr'. Thus, Intel `mov al, byte ptr FOO' is `movb FOO, %al' in AT&T syntax.

Immediate form long jumps and calls are `lcall/ljmp $SECTION, $OFFSET' in AT&T syntax; the Intel syntax is `call/jmp far SECTION:OFFSET'. Also, the far return instruction is `lret $STACK-ADJUST' in AT&T syntax; Intel syntax is `ret far STACK-ADJUST'.

The AT&T assembler does not provide support for multiple section programs. Unix style systems expect all programs to be single sections.


Register Naming

The x86 registers consist of:

 * the 8 32-bit registers `%eax' (the accumulator),`%ebx',`%ecx', `%edx', `%edi', `%esi', `%ebp' (the frame pointer), and `%esp' (the stack pointer).
 * the 8 16-bit low-ends of these: `%ax', `%bx', `%cx', `%dx', `%di', `%si', `%bp', and `%sp'.
 * the 8 8-bit registers: `%ah', `%al', `%bh', `%bl', `%ch', `%cl', `%dh', and `%dl' (These are the high-bytes and low-bytes of `%ax',`%bx', `%cx', and `%dx')
 * the 6 section registers `%cs' (code section), `%ds' (data section), `%ss' (stack section), `%es', `%fs', and `%gs'.
 * the 3 processor control registers `%cr0', `%cr2', and `%cr3'.
 * the 6 debug registers `%db0', `%db1', `%db2', `%db3', `%db6', and `%db7'.
 * the 2 test registers `%tr6' and `%tr7'.
 * the 8 floating point register stack `%st' or equivalently `%st(0)', `%st(1)', `%st(2)', `%st(3)', `%st(4)', `%st(5)', `%st(6)', and `%st(7)'.

These registers are overloaded by 8 MMX registers
`%mm0', `%mm1', `%mm2', `%mm3', `%mm4', `%mm5', `%mm6' and `%mm7'.
 * the 8 SSE (Streaming SIMD Extensions) registers registers
 `%xmm0', `%xmm1', `%xmm2', `%xmm3', `%xmm4', `%xmm5', `%xmm6' and `%xmm7'.

The AMD x86-64 architecture extends the register set by:

 * enhancing the 8 32-bit registers to 64-bit: `%rax' (the accumulator), `%rbx', `%rcx', `%rdx', `%rdi', `%rsi', `%rbp' (the frame pointer), `%rsp' (the stack pointer)
 * the 8 extended registers `%r8'-`%r15'.
 * the 8 32-bit low ends of the extended registers:`%r8d'-`%r15d'
 * the 8 16-bit low ends of the extended registers:`%r8w'-`%r15w'
 * the 8 8-bit low ends of the extended registers: `%r8b'-`%r15b'
 * the 4 8-bit registers: `%sil', `%dil', `%bpl', `%spl'.
 * the 8 debug registers: `%db8'-`%db15'. * the 8 SSE registers: `%xmm8'-`%xmm15'.

First created: May 12, 2004
2nd Edition: April 23, 2007
Last update: Nov 14, 2008

No comments:

Post a Comment