Intel 486 32-bit Address Modes, and Gnu Assembler Syntax Here mem = memory operand = m32 in S&S, p. 72. (32-bit mode case) Note that the [ ] means access memory at the enclosed address, like the * operator for pointer-deferencing in C. Address Mode Intel syntax -----------------------Register ("reg") mov eax, ebx Gnu syntax ---------------movl %ebx, %eax Immediate ("idata") movb $0x3a, %bl mov bl, 3ah Memory Addressing Modes: "mem" in instruction manual Direct mov [1234h], eax movl %eax, 0x1234 mem = [disp32] mov x, eax movl %eax, x Register Indirect mov [ebx], eax mem = [r32] movl %ebx, (%ebx) Register Indirect mov [ebx+4], al with Displacement or mov 4[ebx], al mem = [r32 + disp32] or mov [ebx]+4, al movb %al, 4(%ebx) Scaled Index mov arr[4*edx], eax movl %eax, arr(,%edx,4) mem = [n*r32p + disp32] or mov [4*edx+arr], eax The memory addressing modes above are all important special cases of the general formula at the bottom of page 72. mem = m32 = [r32 + n*r32p + disp32] where -- r32 is any one of eax, ebx, ecx, edx, esi, edi, ebp, esp -- r32p is any r32 reg except esp, and is the "index reg" -- n = 1, 2, 4, or 8, or is omitted, the "scale" -- disp32 = signed 32-bit constant, the "displacement" -- the effective address is r32 + n*r32p + disp32, not m32 (correction to misstatement in text, bottom of p. 72) Thus two registers can be used at once in memory addressing, called "base plus index" addressing. The scaled register (the one multiplied by n) is called the index register and the other the base register. The general expression for mem in Gnu as is: mem = disp32(r32, r32p, n) Gnu syntax, general "mem" case where n defaults to 1 if the third arg is omitted, and no scaling is done if the second arg is omitted. Thus the Gnu ( ) notation also means pointer-dereferencing, with the pointer value r32 + n*r32p + disp32, or "disp32 off from r32 + n*r32p". Some examples using two registers: mov array[ebx+esi], eax movl %eax, array(%ebx,%esi) mov [ebx + 4*esi], eax movl %eax, (%ebx, %esi, 4) mov [ebx+4*esi + vect], eax movl %eax, vect(%ebx, %esi, 4) To confuse matters, the Intel syntax allows several variants: disp[r32 + n*r32p], [r32 + n*r32p]+disp, disp[r32][n*r32p], and even disp1[r32+n*r32p+disp2] (the disp's just add up) Examples by instruction (examples from instruction manual) ADD addb 0x4211a, %al # add contents of byte in mem at addr 4211a, to al addw $34, %ax # immed 34, decimal addl 8(%ebp), %esi AND andb $0x0f, %al andl %eax, %ebx andb 0x7f, 6(%ebx) CALL call sort lea fn)table, %ebx movl $3, %eax call (%ebx, %eax, 4) # advanced use, not to worry about CMP cmpb x, %al # 8-bit compare, mem byte at x vs al cmpw (%ebp,%eax,2), %cx # 16-bit compare, array[i] vs cx, with array addr in ebp, i in eax cmpl $7, %esi # 32-bit compare, contents of esi vs 7 IN inw $0x72, %ax crt_port = 0x1f4 movw $crt_port, %dx inb %dx, %al # 2 bytes in from ports 0x72, 0x73, to ax # (made-up port#) # put port# in dx # 1 byte in from port 0x1f4, to al INC incl %esi INT int $42 # make a system-dependent OS call Jcc Note multiple mneumonics for the same action: je is the same as jz, both test flag ZF. Flags: These instuctions *test* the flags in EFLAGS, but they don't *change* any of them. decb %al jz reached_zero LEA lea vector(,%ebx,4), %esi # load address of dword array element (addr of array is val of symbol "vector", index in ebx) lea (%eax,%ebx), %edi # add contents of eax and ecx, store in edi MOV movb movl movw movb (%eax), %al $0x182, %esi %dx, %bx $0x7f, %ah OUT movw $0xe78, %dx # put port in %dx outb %al, %dx # output byte to port 0xe78, from al PUSH pushl $7 # push 7 (as a dword) onto stack pushl array(,%esi,4) # push dword array element (index in esi) RET ret $4 # but we have the *caller* adjust the stack, to fit with C, so we just use "ret"