I would like to know what the difference between these instructions is:
MOV AX, [TABLE-ADDR]
and
LEA AX, [TABLE-ADDR]
LEA means Load Effective Address
MOV means Load Value
In short, LEA loads a pointer to the item you're addressing whereas MOV loads the actual value at that address.
The purpose of LEA is to allow one to perform a non-trivial address calculation and store the result [for later usage]
LEA ax, [BP+SI+5] ; Compute address of value
MOV ax, [BP+SI+5] ; Load value at that address
Where there are just constants involved, MOV (through the assembler's constant calculations) can sometimes appear to overlap with the simplest cases of usage of LEA. Its useful if you have a multi-part calculation with multiple base addresses etc.
In NASM syntax:
mov eax, var == lea eax, [var] ; i.e. mov r32, imm32
lea eax, [var+16] == mov eax, var+16
lea eax, [eax*4] == shl eax, 2 ; but without setting flags
In MASM syntax, use OFFSET var to get a mov-immediate instead of a load.
The instruction MOV reg,addr means read a variable stored at address addr into register reg. The instruction LEA reg,addr means read the address (not the variable stored at the address) into register reg.
Another form of the MOV instruction is MOV reg,immdata which means read the immediate data (i.e. constant) immdata into register reg. Note that if the addr in LEA reg,addr is just a constant (i.e. a fixed offset) then that LEA instruction is essentially exactly the same as an equivalent MOV reg,immdata instruction that loads the same constant as immediate data.
None of the previous answers quite got to the bottom of my own confusion, so I'd like to add my own.
What I was missing is that lea operations treat the use of parentheses different than how mov does.
Think of C. Let's say I have an array of long that I call array. Now the expression array[i] performs a dereference, loading the value from memory at the address array + i * sizeof(long) [1].
On the other hand, consider the expression &array[i]. This still contains the sub-expression array[i], but no dereferencing is performed! The meaning of array[i] has changed. It no longer means to perform a deference but instead acts as a kind of a specification, telling & what memory address we're looking for. If you like, you could alternatively think of the & as "cancelling out" the dereference.
Because the two use-cases are similar in many ways, they share the syntax array[i], but the existence or absence of a & changes how that syntax is interpreted. Without &, it's a dereference and actually reads from the array. With &, it's not. The value array + i * sizeof(long) is still calculated, but it is not dereferenced.
The situation is very similar with mov and lea. With mov, a dereference occurs that does not happen with lea. This is despite the use of parentheses that occurs in both. For instance, movq (%r8), %r9 and leaq (%r8), %r9. With mov, these parentheses mean "dereference"; with lea, they don't. This is similar to how array[i] only means "dereference" when there is no &.
An example is in order.
Consider the code
movq (%rdi, %rsi, 8), %rbp
This loads the value at the memory location %rdi + %rsi * 8 into the register %rbp. That is: get the value in the register %rdi and the value in the register %rsi. Multiply the latter by 8, and then add it to the former. Find the value at this location and place it into the register %rbp.
This code corresponds to the C line x = array[i];, where array becomes %rdi and i becomes %rsi and x becomes %rbp. The 8 is the length of the data type contained in the array.
Now consider similar code that uses lea:
leaq (%rdi, %rsi, 8), %rbp
Just as the use of movq corresponded to dereferencing, the use of leaq here corresponds to not dereferencing. This line of assembly corresponds to the C line x = &array[i];. Recall that & changes the meaning of array[i] from dereferencing to simply specifying a location. Likewise, the use of leaq changes the meaning of (%rdi, %rsi, 8) from dereferencing to specifying a location.
The semantics of this line of code are as follows: get the value in the register %rdi and the value in the register %rsi. Multiply the latter by 8, and then add it to the former. Place this value into the register %rbp. No load from memory is involved, just arithmetic operations [2].
Note that the only difference between my descriptions of leaq and movq is that movq does a dereference, and leaq doesn't. In fact, to write the leaq description, I basically copy+pasted the description of movq, and then removed "Find the value at this location".
To summarize: movq vs. leaq is tricky because they treat the use of parentheses, as in (%rsi) and (%rdi, %rsi, 8), differently. In movq (and all other instruction except lea), these parentheses denote a genuine dereference, whereas in leaq they do not and are purely convenient syntax.
[1] I've said that when array is an array of long, the expression array[i] loads the value from the address array + i * sizeof(long). This is true, but there's a subtlety that should be addressed. If I write the C code
long x = array[5];
this is not the same as typing
long x = *(array + 5 * sizeof(long));
It seems that it should be based on my previous statements, but it's not.
What's going on is that C pointer addition has a trick to it. Say I have a pointer p pointing to values of type T. The expression p + i does not mean "the position at p plus i bytes". Instead, the expression p + i actually means "the position at p plus i * sizeof(T) bytes".
The convenience of this is that to get "the next value" we just have to write p + 1 instead of p + 1 * sizeof(T).
This means that the C code long x = array[5]; is actually equivalent to
long x = *(array + 5)
because C will automatically multiply the 5 by sizeof(long).
So in the context of this StackOverflow question, how is this all relevant? It means that when I say "the address array + i * sizeof(long)", I do not mean for "array + i * sizeof(long)" to be interpreted as a C expression. I am doing the multiplication by sizeof(long) myself in order to make my answer more explicit, but understand that due to that, this expression should not be read as C. Just as normal math that uses C syntax.
[2] Side note: because all lea does is arithmetic operations, its arguments don't actually have to refer to valid addresses. For this reason, it's often used to perform pure arithmetic on values that may not be intended to be dereferenced. For instance, cc with -O2 optimization translates
long f(long x) {
return x * 5;
}
into the following (irrelevant lines removed):
f:
leaq (%rdi, %rdi, 4), %rax # set %rax to %rdi + %rdi * 4
ret
If you only specify a literal, there is no difference. LEA has more abilities, though, and you can read about them here:
http://www.oopweb.com/Assembly/Documents/ArtOfAssembly/Volume/Chapter_6/CH06-1.html#HEADING1-136
It depends on the used assembler, because
mov ax,table_addr
in MASM works as
mov ax,word ptr[table_addr]
So it loads the first bytes from table_addr and NOT the offset to table_addr. You should use instead
mov ax,offset table_addr
or
lea ax,table_addr
which works the same.
lea version also works fine if table_addr is a local variable e.g.
some_procedure proc
local table_addr[64]:word
lea ax,table_addr
As stated in the other answers:
MOV will grab the data at the address inside the brackets and place that data into the destination operand.
LEA will perform the calculation of the address inside the brackets and place that calculated address into the destination operand. This happens without actually going out to the memory and getting the data. The work done by LEA is in the calculating of the "effective address".
Because memory can be addressed in several different ways (see examples below), LEA is sometimes used to add or multiply registers together without using an explicit ADD or MUL instruction (or equivalent).
Since everyone is showing examples in Intel syntax, here are some in AT&T syntax:
MOVL 16(%ebp), %eax /* put long at ebp+16 into eax */
LEAL 16(%ebp), %eax /* add 16 to ebp and store in eax */
MOVQ (%rdx,%rcx,8), %rax /* put qword at rcx*8 + rdx into rax */
LEAQ (%rdx,%rcx,8), %rax /* put value of "rcx*8 + rdx" into rax */
MOVW 5(%bp,%si), %ax /* put word at si + bp + 5 into ax */
LEAW 5(%bp,%si), %ax /* put value of "si + bp + 5" into ax */
MOVQ 16(%rip), %rax /* put qword at rip + 16 into rax */
LEAQ 16(%rip), %rax /* add 16 to instruction pointer and store in rax */
MOVL label(,1), %eax /* put long at label into eax */
LEAL label(,1), %eax /* put the address of the label into eax */
Basically ... "Move into REG ... after computing it..."
it seems to be nice for other purposes as well :)
if you just forget that the value is a pointer
you can use it for code optimizations/minimization ...what ever..
MOV EBX , 1
MOV ECX , 2
;//with 1 instruction you got result of 2 registers in 3rd one ...
LEA EAX , [EBX+ECX+5]
EAX = 8
originaly it would be:
MOV EAX, EBX
ADD EAX, ECX
ADD EAX, 5
Lets understand this with a example.
mov eax, [ebx]
and
lea eax, [ebx]
Suppose value in ebx is 0x400000. Then mov will go to address 0x400000 and copy 4 byte of data present their to eax register.Whereas lea will copy the address 0x400000 into eax. So, after the execution of each instruction value of eax in each case will be (assuming at memory 0x400000 contain is 30).
eax = 30 (in case of mov)
eax = 0x400000 (in case of lea)
For definition mov copy the data from rm32 to destination (mov dest rm32) and lea(load effective address) will copy the address to destination (mov dest rm32).
MOV can do same thing as LEA [label], but MOV instruction contain the effective address inside the instruction itself as an immediate constant (calculated in advance by the assembler). LEA uses PC-relative to calculate the effective address during the execution of the instruction.
LEA (Load Effective Address) is a shift-and-add instruction. It was added to 8086 because hardware is there to decode and calculate adressing modes.
The difference is subtle but important. The MOV instruction is a 'MOVe' effectively a copy of the address that the TABLE-ADDR label stands for. The LEA instruction is a 'Load Effective Address' which is an indirected instruction, which means that TABLE-ADDR points to a memory location at which the address to load is found.
Effectively using LEA is equivalent to using pointers in languages such as C, as such it is a powerful instruction.
Related
I came across an exercise, as I am still trying to familiarise myself with assembly code.
I am unsure how to derive the types for a given struct, given the assembly code and the skeleton c code. Could someone teach me how this should be done?
This is the assembly code, where rcx and rdx hold the arguments i and j respectively.
randFunc:
movslq %ecx,%rcx // move i into rcx
movslq %edx, %rdx // move j into rdx
leaq (%rcx,%rcx,2), %rax //3i into rax
leaq (%rdx,%rdx,2), %rdx // 3j into rdx
salq $5, %rax // shift arith left 32? so 32*3i = 96i
leaq (%rax,%rdx,8), %rax //24j + 96i into rax
leaq matrixtotest(%rip), %rdx //store address of the matrixtotest in rdx
addq %rax, %rdx //jump to 24th row, 6th column variable
cmpb $10, 2(%rdx) //add 2 to that variable and compare to 10
jg .L5 //if greater than 10 then go to l5
movq 8(%rdx), %rax // else add 8 to the rdx number and store in rax
movzwl (%rdx), %edx //move the val in rdx (unsigned) to edx as an int
subl %edx, %eax //take (val+8) -(val) = 8? (not sure)
ret
.L5
movl 16(%rdx),%eax //move 1 row down and return? not sure about this
ret
This is the C code:
struct mat{
typeA a;
typeB b;
typeC c;
typeD d;
}
struct mat matrixtotest[M][N];
int randFunc(int i, int j){
return __1__? __2__ : __3__;
}
How do I derive the types of the variables a,b,c,d? And what is happening in the 1) 2) 3) parts of the return statement ?
Please help me, I'm very confused about what's happening and how to derive the types of the struct from this assembly.
Any help is appreciated, thank you.
Due to the cmpb $10, 2(%rdx) you have a byte sized something at offset 2. Due to the movzwl (%rdx), %edx you have a 2 byte sized unsigned something at offset 0. Due to the movq 8(%rdx), %rax you have a 8 byte sized something at offset 8. Finally due to the movl 16(%rdx),%eax you have a 4 byte sized something at offset 16. Now sizes don't map to types directly, but one possibility would be:
struct mat{
uint16_t a;
int8_t b;
int64_t c;
int32_t d;
};
You can use unsigned short, signed char, long, int if you know their sizes.
The size of the structure is 24 bytes, with padding at the end due to alignment requirement of the 8 byte field. From the 96i you can deduce N=4 probably. M is unknown. As such 24j + 96i accesses item matrixtotest[i][j]. The rest should be clear.
How do I derive the types of the variables a,b,c,d?
You want to see how variables are used, which will give you a very strong indication as to their size & sign. (These indications are not always perfect, but the best we can do with limited information, i.e. missing source code, and will suffice for your exercise.)
So, just work the code, one instruction after another to see what they do by the definitions they have in the assembler and their mapping to the instruction set, paying particular attention to the sizes, signs, and offsets specified by the instructions.
Let's start for example with the first instruction: movslq ecx, rcx — this is saying that the first parameter (which is found in ecx), is a 32-bit signed number.
Since rcx is Windows ABI first parameter, and the assembly code is asking for ecx to be sign extended into rcx, then we know that this parameter is a signed 32-bit integer. And you proceed to the next instruction, to glean what you can from it — and so on.
And what is happening in the 1) 2) 3) parts of the return statement ?
The ?: operator is a ternary operator known as a conditional. If the condition, placeholder __1__, is true, it will choose the __2__ value and if false it will choose __3__. This is usually (but not always) organized as an if-then-else branching pattern, where the then-part represents placeholder __2__ and the else part placeholder __3__.
That if-then-else branching pattern looks something like this in assembly/machine code:
if <condition> /* here __1__ */ is false goto elsePart;
<then-part> // here __2__
goto ifDone;
elsePart:
<else-part> // here __3__
ifDone:
So, when you get to an if-then-else construct, you can fit that into the ternary operator place holders.
That code is nicely commented, but somewhat absent size, sign, and offset information. So, following along and derive that missing information from the way the instructions tell the CPU what sizes, signs, and offsets to use.
As Jester describes, if the code indexes into the array, because it is two-dimensional, it uses two indexes. The indexing takes the given indexes and computes the address of the element. As such, the first index finds the row, and so must skip ahead one row for each value in the index. The second index must skip ahead one element for each value in the index. Thus, by the formula in the comments: 24j + 96i, we can say that a row is 96 bytes long and an element (the struct) is 24 bytes long.
I'm still uncertain how registers are being used by the assembler
say I have a program:
int main(int rdi, int rsi, int rdx) {
rdx = rdi;
return 0;
}
Would this in assembly be translated into:
movq %rdx, %rdi
ret rax;
I'm new to AT&T and have hard time predicting when a certain register will be used.
Looking at this chart from Computer Systems - A programmer's perspective, third edition, R.E. Bryant and D. R. O'Hallaron:
charter
Is it certain in which register arguments and variables are stored?
Only at entry and exit of a function.
There is no guarantee as to what registers will be used within a function, even for variables which are parameters to the function. Compilers can (and often will) move variables around between registers to optimize register/stack usage, especially on register-starved architectures like x86.
In this case, a simple assignment operation like rdx = rdi may not compile to any assembly code at all, because the compiler will simply recognize that both values can now be found in the register %rdi. Even for a more complex operation like rdx = rdi + 1, the compiler has the freedom to store the value in any register, not specifically in %rdx. (It may even store the value back to %rdi, e.g. inc %rdi, if it recognizes that the original value is never used afterwards.)
No, it would be translated into:
mov %rdi, %rdx # move %rdi into %rdx
xor %eax, %eax # zero return value
ret # return
Of course, it's more than likely that rdx = rdi (and therefore mov %rdi, %rdx) will be removed by the compiler, because rdx is not used again.
Credit to #Jester for finding this out before me.
For a task at my school, I need to write a C Program which does a 16 bit addition using an assembly programm. Besides the result the EFLAGS shall also be returned.
Here is my C Program:
int add(int a, int b, unsigned short* flags);//function must be used this way
int main(void){
unsigned short* flags = NULL;
printf("%d\n",add(30000, 36000, flags);// printing just the result
return 0;
}
For the moment the Program just prints out the result and not the flags because I am unable to get them.
Here is the assembly program for which I use NASM:
global add
section .text
add:
push ebp
mov ebp,esp
mov ax,[ebp+8]
mov bx,[ebp+12]
add ax,bx
mov esp,ebp
pop ebp
ret
Now this all works smoothly. But I have no idea how to get the pointer which must be at [ebp+16] pointing to the flag register. The professor said we will have to use the pushfd command.
My problem just lies in the assembly code. I will modify the C Program to give out the flags after I get the solution for the flags.
Normally you'd just use a debugger to look at flags, instead of writing all the code to get them into a C variable for a debug-print. Especially since decent debuggers decode the condition flags symbolically for you, instead of or as well as showing a hex value.
You don't have to know or care which bit in FLAGS is CF and which is ZF. (This information isn't relevant for writing real programs, either. I don't have it memorized, I just know which flags are tested by different conditions like jae or jl. Of course, it's good to understand that FLAGS are just data that you can copy around, save/restore, or even modify if you want)
Your function args and return value are int, which is 32-bit in the System V 32-bit x86 ABI you're using. (links to ABI docs in the x86 tag wiki). Writing a function that only looks at the low 16 bits of its input, and leaves high garbage in the high 16 bits of the output is a bug. The int return value in the prototype tells the compiler that all 32 bits of EAX are part of the return value.
As Michael points out, you seem to be saying that your assignment requires using a 16-bit ADD. That will produce carry, overflow, and other conditions with different inputs than if you looked at the full 32 bits. (BTW, this article explains carry vs. overflow very well.)
Here's what I'd do. Note the 32-bit operand size for the ADD.
global add
section .text
add:
push ebp
mov ebp,esp ; stack frames are optional, you can address things relative to ESP
mov eax, [ebp+8] ; first arg: No need to avoid loading the full 32 bits; the next insn doesn't care about the high garbage.
add ax, [ebp+12] ; low 16 bits of second arg. Operand-size implied by AX
cwde ; sign-extend AX into EAX
mov ecx, [ebp+16] ; the pointer arg
pushf ; the simple straightforward way
pop edx
mov [ecx], dx ; Store the low 16 of what we popped. Writing word [ecx] is optional, because dx implies 16-bit operand-size
; be careful not to do a 32-bit store here, because that would write outside the caller's object.
; mov esp,ebp ; redundant: ESP is still pointing at the place we pushed EBP, since the push is balanced by an equal-size pop
pop ebp
ret
CWDE (the 16->32 form of the 8086 CBW instruction) is not to be confused with CWD (the AX -> DX:AX 8086 instruction). If you're not using AX, then MOVSX / MOVZX are a good way to do this.
The fun way: instead of using the default operand size and doing 32-bit push and pop, we can do a 16-bit pop directly into the destination memory address. That would leave the stack unbalanced, so we could either uncomment the mov esp, ebp again, or use a 16-bit pushf (with an operand-size prefix, which according to the docs makes it only push the low 16 FLAGS, not the 32-bit EFLAGS.)
; What I'd *really* do: maximum efficiency if I had to use the 32-bit ABI with args on the stack, instead of args in registers
global add
section .text
add:
mov eax, [esp+4] ; first arg, first thing above the return address
add ax, [esp+8] ; second arg
cwde ; sign-extend AX into EAX
mov ecx, [esp+12] ; the pointer
pushfw ; push the low 16 of FLAGS
pop word [ecx] ; pop into memory pointed to by unsigned short* flags
ret
Both PUSHFW and POP WORD will assemble with an operand-size prefix. output from objdump -Mintel, which uses slightly different syntax from NASM:
4000c0: 66 9c pushfw
4000c2: 66 8f 01 pop WORD PTR [ecx]
PUSHFW is the same as o16 PUSHF. In NASM, o16 applies the operand-size prefix.
If you only needed the low 8 flags (not including OF), you could use LAHF to load FLAGS into AH and store that.
PUSHFing directly into the destination is not something I'd recommend. Temporarily pointing the stack at some random address is not safe in general. Programs with signal handlers will use the space below the stack asynchronously. This is why you have to reserve stack space before using it with sub esp, 32 or whatever, even if you're not going to make a function call that would overwrite it by pushing more stuff on the stack. The only exception is when you have a red-zone.
You C caller:
You're passing a NULL pointer, so of course your asm function segfaults. Pass the address of a local to give the function somewhere to store to.
int add(int a, int b, unsigned short* flags);
int main(void) {
unsigned short flags;
int result = add(30000, 36000, &flags);
printf("%d %#hx\n", result, flags);
return 0;
}
This is just a simple approach. I didn't test it, but you should get the idea...
Just set ESP to the pointer value, increment it by 2 (even for 32-bit arch) and PUSHF like this:
global add
section .text
add:
push ebp
mov ebp,esp
mov ax,[ebp+8]
mov bx,[ebp+12]
add ax,bx
; --- here comes the mod
mov esp, [ebp+16] ; this will set ESP to the pointers address "unsigned short* flags"
lea esp, [esp+2] ; adjust ESP to address above target
db 66h ; operand size prefix for 16-bit PUSHF (alternatively 'db 0x66', depending on your assembler
pushf ; this will save the lower 16-bits of EFLAGS to WORD PTR [EBP+16] = [ESP+2-2]
; --- here ends the mod
mov esp,ebp
pop ebp
ret
This should work, because PUSHF decrements ESP by 2 and then saves the value to WORD PTR [ESP]. Therefore it had to be increased before using the pointer address. Setting ESP to the appropriate value enables you to denominate the direct target of PUSHF.
I'm trying to get a better understanding of how compilers produce code for undefined expressions e.g. for the following code:
int main()
{
int i = 5;
i = i++;
return 0;
}
This is the assembler code generated by gcc 4.8.2 (Optimisation is off -O0 and I’ve inserted my own line numbers for reference purposes):
(gdb) disassemble main
Dump of assembler code for function main:
(1) 0x0000000000000000 <+0>: push %rbp
(2) 0x0000000000000001 <+1>: mov %rsp,%rbp
(3) 0x0000000000000004 <+4>: movl $0x5,-0x4(%rbp)
(4) 0x000000000000000b <+11>: mov -0x4(%rbp),%eax
(5) 0x000000000000000e <+14>: lea 0x1(%rax),%edx
(6) 0x0000000000000011 <+17>: mov %edx,-0x4(%rbp)
(7) 0x0000000000000014 <+20>: mov %eax,-0x4(%rbp)
(8) 0x0000000000000017 <+23>: mov $0x0,%eax
(9) 0x000000000000001c <+28>: pop %rbp
(10) 0x000000000000001d <+29>: retq
End of assembler dump.
Execution of this code results in the value of i remaining at the value of 5 (verified with a printf() statement) i.e. i doesn't appear to ever be incremented. I understand that different compilers will evaluate/compile undefined expressions in differnet ways and this may just be the way that gcc does it i.e. I could get a different result with a different compiler.
With respect to the assembler code, as I understand:
Ignoring line - 1-2 setting up of stack/base pointers etc.
line 3/4 - is how the value of 5 is assigned to i.
Can anyone explain what is happening on line 5-6? It looks as if i will be ultimately reassigned the value of 5 (line 7), but is the increment operation (required for the post increment operation i++) simply abandoned/skipped by the compiler in the case?
These three lines contain your answer:
lea 0x1(%rax),%edx
mov %edx,-0x4(%rbp)
mov %eax,-0x4(%rbp)
The increment operation isn't skipped. lea is the increment, taking the value from %rax and storing the incremented value in %edx. %edx is stored but then overwritten by the next line which uses the original value from %eax.
They key to understanding this code is to know how lea works. It stands for load effective address, so while it looks like a pointer dereference, it actually just does the math needed to get the final address of [whatever], and then keeps the address, instead of the value at that address. This means it can be used for any mathematical expression that can be expressed efficiently using addressing modes, as an alternative to mathematical opcodes. It's frequently used as a way to get a multiply and add into a single instruction for this reason. In particular, in this case it's used to increment the value and move the result to a different register in one instruction, where inc would instead overwrite it in-place.
Line 5-6, is the i++. The lea 0x1(%rax),%edx is i + 1 and mov %edx,-0x4(%rbp) writes that back to i. However line 7, the mov %eax,-0x4(%rbp) writes the original value back into i. The code looks like:
(4) eax = i
(5) edx = i + 1
(6) i = edx
(7) i = eax
I get that xor is exclusive or and can be used for
xorl %ebx %ebx can be used to clear the register
however while reading I came across a different usage of xorl and am confused.
xorl 12(%ebp),%eax which meant eax = x^y
in this context its used for the exponentiation of x. Is this incorrect usage? Thanks.
Here ^ means XOR, as is used in C.
Assuming we are using AT&T notation, then
xorl 12(%ebp), %eax
will xor eax with the value 12 bytes from ebp (if I remember my assembler right), which would normally be a local variable. So, it would be more correct to say
eax ^= y
(assuming y is at ebp+12), or
x ^= y
if x is stored in the eax register.