x86 architecture
- We will start with the original 16-bit 8086 CPU (1978)
- CPU runs instructions:
for(;;){
run next instruction
}
- Needs work space: registers
- four 16-bit data registers: AX, BX, CX, DX
- each in two 8-bit halves, e.g. AH and AL
- very fast, very few (there's limited space on chip!)
- More work space: memory
- CPU sends out address on address lines (wires, one bit per wire)
- Data comes back on data lines or is written to data lines
- much slower than registers (~100 cycles vs. a few cycles)
- Add address registers: pointers into memory
- SP - stack pointer
- BP - frame base pointer
- SI - source index
- DI - destination index
- Instructions are in memory too!
- IP - instruction pointer (also called PC on some older machines)
- increment after running each instruction
- can be modified by CALL, RET, JMP, conditional jumps
- Want conditional jumps
- FLAGS register hold various condition codes
- whether last arithmetic operation overflowed
- ... was positive/negative
- ... was [not] zero
- ... carry/borrow on add/subtract
- ... etc.
- whether interrupts are enabled
- direction of data copy instructions
- J[N]Z, J[N]C, J[N]O ...
- Still not interesting - need I/O to interact with outside world
- Original PC architecture: use dedicated I/O space
- Works same as memory accesses but set I/O signal
- Only 1024 I/O addresses
- Accessed with special instructions (IN, OUT)
- Example: write a byte to line printer:
#define DATA_PORT 0x378
#define STATUS_PORT 0x379
#define BUSY 0x80
#define CONTROL_PORT 0x37A
#define STROBE 0x01
void
lpt_putc(int c)
{
/* wait for printer to consume previous byte */
while((inb(STATUS_PORT) & BUSY) == 0)
;
/* put the byte on the parallel lines */
outb(DATA_PORT, c);
/* tell the printer to look at the data */
outb(CONTROL_PORT, STROBE);
outb(CONTROL_PORT, 0);
}
- Memory-Mapped I/O
- Use normal physical memory addresses
- Gets around limited size of I/O address space
- No need for special instructions
- System controller routes to appropriate device
- Works like ``magic'' memory:
- Addressed and accessed like memory,
but ...
- ... does not behave like memory!
- Reads and writes can have ``side effects''
- Read results can change due to external events
- What if we want to use more than 2^16 bytes of memory?
- 8086 has 20-bit physical addresses, can have 1 Meg RAM
- the extra four bits usually come from a 16-bit "segment register":
- CS - code segment, for fetches via IP
- SS - stack segment, for load/store via SP and BP
- DS - data segment, for load/store via other registers
- ES - another data segment, destination for string operations
- virtual to physical translation: pa = va + seg*16
- e.g. set CS = 4096 to execute starting at 65536
- a far pointer includes full segment:offset
- tricky: pointer arithmetic and array indexing across segment boundaries
- But 8086's 16-bit addresses and data were still painfully small
- 80386 added support for 32-bit data and addresses (1985)
- boots in 16-bit real mode and switches to 32-bit protected mode
- registers are 32 bits wide, called EAX rather than AX
- 32-bit operands and addresses, e.g. ADD does 32-bit arithmetic
- prefixes 0x66/0x67 toggle between 16-bit and 32-bit operands and addresses: in 32-bit mode, MOVW is expressed as 0x66 MOVW
- the .code32 in boot.S tells assembler to generate 0x66 for e.g. MOVW
- 80386 also changed segments and added paged memory...
- Example instruction encoding
b8 cd ab 16-bit CPU, AX <- 0xabcd
b8 34 12 cd ab 32-bit CPU, EAX <- 0xabcd1234
66 b8 cd ab 32-bit CPU, AX <- 0xabcd
x86 Physical Memory Map
- The physical address space mostly looks like ordinary RAM
- Except some low-memory addresses actually refer to other things
- Writes to VGA memory appear on the screen
+------------------+ <- 0xFFFFFFFF (4GB)
| 32-bit |
| memory mapped |
| devices |
| |
/\/\/\/\/\/\/\/\/\/\
/\/\/\/\/\/\/\/\/\/\
| |
| Unused |
| |
+------------------+ <- depends on amount of RAM
| |
| |
| Extended Memory |
| |
| |
+------------------+ <- 0x00100000 (1MB)
| BIOS ROM |
+------------------+ <- 0x000F0000 (960KB)
| 16-bit devices, |
| expansion ROMs |
+------------------+ <- 0x000C0000 (768KB)
| VGA Display |
+------------------+ <- 0x000A0000 (640KB)
| |
| Low Memory |
| |
+------------------+ <- 0x00000000
x86 Instruction Set
- Intel syntax: op dst, src (Intel manuals, PC assembly book)
- AT&T (gcc/gas) syntax: op src, dst (Mini-labs)
- uses b, w, l suffix on instructions to specify size of operands
- Operands are registers, constant, memory via register, memory via constant
- Examples:
AT&T syntax | "C"-ish equivalent
|
movl %eax, %edx | edx = eax; | register mode
|
movl $0x123, %edx | edx = 0x123; | immediate
|
movl 0x123, %edx | edx = *(int32_t*)0x123; | direct
|
movl (%ebx), %edx | edx = *(int32_t*)ebx; | indirect
|
movl 4(%ebx), %edx | edx = *(int32_t*)(ebx+4); | displaced
|
- Instruction classes
- data movement: MOV, PUSH, POP, ...
- arithmetic: TEST, SHL, ADD, AND, ...
- i/o: IN, OUT, ...
- control: JMP, JZ, JNZ, CALL, RET
- string: REP MOVSB, ...
- system: IRET, INT
- For more info, check out Intel architecture manual Volume 2 in the reference materials.
gcc x86 calling conventions