I am a little bit confused about the difference between
leal -4(%ebp), %eax
and
movl -4(%ebp), %eax
Can someone explain this to me?
LEA (load effective address) just computes the address of the operand, it does not actually dereference it. Most of the time, it's just doing a calculation like a combined multiply-and-add for, say, array indexing.
In this case, it's doing a simple numeric subtraction: leal -4(%ebp), %eax just assigns to the %eax register the value of %ebp - 4. It's equivalent to a single sub instruction, except a sub requires the destination to be the same as one of the sources.
The movl instruction, in contrast, accesses the memory location at %ebp - 4 and stores that value into %eax.
If you wish to look at this in terms of a different programming language, then:
int var;
[ ... ]
func (var, &var);
evaluates to the following (Linux x86_64) assembly code:
[ ... ]
4: 8b 7c 24 0c mov 0xc(%rsp),%edi
8: 48 8d 74 24 0c lea 0xc(%rsp),%rsi
d: e8 xx xx xx xx callq ... <func>
[ ... ]
Since %rdi / %rsi are the 1st / 2nd arguments, you can see that lea ... retrieves the address &var of a variable, while mov ... loads/stores the value var of the same.
I.e. in assembly, the use of lea instead of mov is similar to using the address-of & operator in C/C++, not the (value of) a variable itself.
lea has far more uses than that, but you explicitly asked about the difference between the two.
For illustration: mov with a memory operand always performs a memory access (load or store), while the memory operand to lea is merely treated as pointer arithmetic - i.e. the address is calculated and resolved but no memory access happens at the instruction itself. These two:
lea 1234(%eax, %ebx, 8), %ecx
movl (%ecx), ecx
result in the same as:
movl 1234(%eax, %ebx, 8), %ecx
while the following:
leal (%eax, %eax, 4), %eax
multiplies the value in %eax with five.
Equivialent to LEA in Intel syntax, load effective address (long?).
Related
Let's say .data section has following item:
0x1234 00010203 04050607 08090a0b 0c0d0e0f
0x1238 10000000
And in code,
mov $0x1234, %eax
mov 0x1238, %ebx
I believe with $ symbol, it would be constant number, so %eax will have memory address, but what about %ebx?
What exactly different between two instruction?
The difference is that with $ it's the numeric value while without $ it's the contents of memory at that address
If argument of instruction is without any special marker (such as % for register or $ for numeric constant), then it is memory access. So following:
movl 10, %eax
movl foo, %eax
Corresponds to intel syntax:
mov eax, [10]
mov eax, [foo]
To use numeric constant, or use address of label, there is $ operator:
movl $10, %eax
movl $foo, %eax
In Intel syntax:
mov eax, 10
mov eax, offset foo
http://x86asm.net/articles/what-i-dislike-about-gas/
I'm trying to understand assembly in x86 more. I have a mystery function here that I know returns an int and takes an int argument.
So it looks like int mystery(int n){}. I can't figure out the function in C however. The assembly is:
mov %edi, %eax
lea 0x0(,%rdi, 8), %edi
sub %eax, %edi
add $0x4, %edi
callq < mystery _util >
repz retq
< mystery _util >
mov %edi, %eax
shr %eax
and $0x1, %edi
and %edi, %eax
retq
I don't understand what the lea does here and what kind of function it could be.
The assembly code appeared to be computer generated, and something that was probably compiled by GCC since there is a repz retq after an unconditional branch (call). There is also an indication that because there isn't a tail call (jmp) instead of a call when going to mystery_util that the code was compiled with -O1 (higher optimization levels would likely inline the function which didn't happen here). The lack of frame pointers and extra load/stores indicated that it isn't compiled with -O0
Multiplying x by 7 is the same as multiplying x by 8 and subtracting x. That is what the following code is doing:
lea 0x0(,%rdi, 8), %edi
sub %eax, %edi
LEA can compute addresses but it can be used for simple arithmetic as well. The syntax for a memory operand is displacement(base, index, scale). Scale can be 1, 2, 4, 8. The computation is displacement + base + index * scale. In your case lea 0x0(,%rdi, 8), %edi is effectively EDI = 0x0 + RDI * 8 or EDI = RDI * 8. The full calculation is n * 7 - 4;
The calculation for mystery_util appears to simply be
n &= (n>>1) & 1;
If I take all these factors together we have a function mystery that passes n * 7 - 4 to a function called mystery_util that returns n &= (n>>1) & 1.
Since mystery_util returns a single bit value (0 or 1) it is reasonable that bool is the return type.
I was curious if I could get a particular version of GCC with optimization level 1 (-O1) to reproduce this assembly code. I discovered that GCC 4.9.x will yield this exact assembly code for this given C program:
#include<stdbool.h>
bool mystery_util(unsigned int n)
{
n &= (n>>1) & 1;
return n;
}
bool mystery(unsigned int n)
{
return mystery_util (7*n+4);
}
The assembly output is:
mystery_util:
movl %edi, %eax
shrl %eax
andl $1, %edi
andl %edi, %eax
ret
mystery:
movl %edi, %eax
leal 0(,%rdi,8), %edi
subl %eax, %edi
addl $4, %edi
call mystery_util
rep ret
You can play with this code on godbolt.
Important Update - Version without bool
I apparently erred in interpreting the question. I assumed the person asking this question determined by themselves that the prototype for mystery was int mystery(int n). I thought I could change that. According to a related question asked on Stackoverflow a day later, it seems int mystery(int n) is given to you as the prototype as part of the assignment. This is important because it means that a modification has to be made.
The change that needs to be made is related to mystery_util. In the code to be reverse engineered are these lines:
mov %edi, %eax
shr %eax
EDI is the first parameter. SHR is logical shift right. Compilers would only generate this if EDI was an unsigned int (or equivalent). int is a signed type an would generate SAR (arithmetic shift right). This means that the parameter for mystery_util has to be unsigned int (and it follows that the return value is likely unsigned int. That means the code would look like this:
unsigned int mystery_util(unsigned int n)
{
n &= (n>>1) & 1;
return n;
}
int mystery(int n)
{
return mystery_util (7*n+4);
}
mystery now has the prototype given by your professor (bool is removed) and we use unsigned int for the parameter and return type of mystery_util. In order to generate this code with GCC 4.9.x I found you need to use -O1 -fno-inline. This code can be found on godbolt. The assembly output is the same as the version using bool.
If you use unsigned int mystery_util(int n) you would discover that it doesn't quite output what we want:
mystery_util:
movl %edi, %eax
sarl %eax ; <------- SAR (arithmetic shift right) is not SHR
andl $1, %edi
andl %edi, %eax
ret
The LEA is just a left-shift by 3, and truncating the result to 32 bit (i.e. zero-extending EDI into RDI implicilty). x86-64 System V passes the first integer arg in RDI, so all of this is consistent with one int arg. LEA uses memory-operand syntax and machine encoding, but it's really just a shift-and-add instruction. Using it as part of a multiply by a constant is a common compiler optimization for x86.
The compiler that generated this function missed an optimization here; the first mov could have been avoided with
lea 0x0(,%rdi, 8), %eax # n << 3 = n*8
sub %edi, %eax # eax = n*7
lea 4(%rax), %edi # rdi = 4 + n*7
But instead, the compiler got stuck on generating n*7 in %edi, probably because it applied a peephole optimization for the constant multiply too late to redo register allocation.
mystery_util returns the bitwise AND of the low 2 bits of its arg, in the low bit, so a 0 or 1 integer value, which could also be a bool.
(shr with no count means a count of 1; remember that x86 has a special opcode for shifts with an implicit count of 1. 8086 only has counts of 1 or cl; immediate counts were added later as an extension and the implicit-form opcode is still shorter.)
The LEA performs an address computation, but instead of dereferencing the address, it stores the computed address into the destination register.
In AT&T syntax, lea C(b,c,d), reg means reg = C + b + c*d where C is a constant, and b,c are registers and d is a scalar from {1,2,4,8}. Hence you can see why LEA is popular for simple math operations: it does quite a bit in a single instruction. (*includes correction from prl's comment below)
There are some strange features of this assembly code: the repz prefix is only strictly defined when applied to certain instructions, and retq is not one of them (though the general behavior of the processor is to ignore it). See Michael Petch's comment below with a link for more info. The use of lea (,rdi,8), edi followed by sub eax, edi to compute arg1 * 7 also seemed strange, but makes sense once prl noted the scalar d had to be a constant power of 2. In any case, here's how I read the snippet:
mov %edi, %eax ; eax = arg1
lea 0x0(,%rdi, 8), %edi ; edi = arg1 * 8
sub %eax, %edi ; edi = (arg1 * 8) - arg1 = arg1 * 7
add $0x4, %edi ; edi = (arg1 * 7) + 4
callq < mystery _util > ; call mystery_util(arg1 * 7 + 4)
repz retq ; repz prefix on return is de facto nop.
< mystery _util >
mov %edi, %eax ; eax = arg1
shr %eax ; eax = arg1 >> 1
and $0x1, %edi ; edi = 1 iff arg1 was odd, else 0
and %edi, %eax ; eax = 1 iff smallest 2 bits of arg1 were both 1.
retq
Note the +4 on the 4th line is entirely spurious. It cannot affect the outcome of mystery_util.
So, overall this ASM snippet computes the boolean (arg1 * 7) % 4 == 3.
I'm studying for a midterm tomorrow and one of the questions on a previous midterm is:
Consider the following C function. Write the corresponding assembly language function to perform the same operation.
int myFunction (int a)
{
return (a + 30);
}
What I wrote down is:
.global _myFunction
_myFunction:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %edx
lea ($30, %edx), %eax
leave
ret
where a is edx and a+30 would be eax. Is the use of lea correct in this case? Would it instead need to be
lea ($30, %edx, 1), %eax
Thanks.
If you are looking to simply add 30 using leal then you should do it this way:
leal 30(%edx), %eax
The notation is displacement(baseregister, offsetregister, scalarmultiplier). The displacement is placed on the outside. 30 is added to edx and stored in eax. In AT&T/GAS notation you can leave off both the offset and multiplier. In our example this leaves us with the equivalent of base + displacement or edx + 30 in this example.
cHao also brings up a good point. Let us say the professor asks you to optimize your code. There are some inefficiencies in the fact that myFunction uses no local variables and doesn't need stack space for itself. Because of that all the stack frame creation and destruction can be removed. If you remove the stack frame then you no longer push %ebp as well. That means your first parameter int a is at 4(%esp) . With that in mind your function can be reduced to something this simple:
.global _myFunction
_myFunction:
movl 4(%esp), %eax
addl $30, %eax
ret
Of course the moment you change your function so that it needs to store things on the stack you would have to put the stack frame code back in (pushl %ebp, pushl %ebp, leave etc)
This question already has an answer here:
Pointers in Assembly
(1 answer)
Closed 9 years ago.
As an assignment, I must read the assembly code and write its high-level C program. The structure in this case is a switch statement, so for each case, the assembly code is translated to the case in C code. Below will only be one of the cases. If you can help me interpret this, it should give me a better understanding of the rest of the cases.
p1 is in %ebp+8
p2 is in %ebp+12
action is in %ebp+16
result is in %edx
...
.L13:
movl 8(%ebp), %eax # get p1
movl (%eax), %edx # result = *p1?
movl 12(%ebp), %ecx # get p2
movl (%ecx), %eax # p1 = *p2
movl 8(%ebp), %ecx # p2 = p1
movl %eax, (%ecx) # *p1 = *p2?
jmp .L19 #jump to default
...
.L19
movl %edx, %eax # set return value
Of course, the comments were added by me to try to make sense of it, except it leaves me more confused. Is this meant to be a swap? Probably not; the formatting would be different. What really happens in the 2nd and 6th lines? Why is %edx only changed once so early if it's the return value? Please answer with some guidelines to interpreting this code.
The above snippet is x86_32 assembly in the (IMO broken) AT&T syntax.
AT&T syntax attaches a size suffix to every operand.
movl means a 32 bit operand. (l for long)
movw means 16 bit operand (w for word)
movb means an 8 bit operand (b for byte)
The operands are reversed in order, so the destination is on the right and the source is on the left.
This is opposite to almost every other programming language.
Register names are prefixed by a % to distinguish them from variable names.
If a register is surrounded by brackets () that means that the memory address pointed to by the register is used, rather than the value inside the register itself.
This makes sense, because EBP is used as a pointer to a stackframe.
Stackframes are used to access parameters and local variables in functions.
Instead of writing: mov eax, dword ptr [ebp+8] (Intel syntax)
AT&T syntax lists it as: movl 8(%ebp), %eax (gas syntax)
Which means: put the contends of the memory address pointed to by (ebp + 8) into eax.
Here's the translation:
.L13: <<-- label used as a jump target.
movl 8(%ebp), %eax <<-- p1, stored at ebp+8 goes into EAX
movl (%eax), %edx <<-- p1 is a pointer, EDX = p1->next
movl 12(%ebp), %ecx <<-- p2, stored at ebp+12 goes in ECX
movl (%ecx), %eax <<-- p2 is (again) a pointer, EAX = p2->next
movl 8(%ebp), %ecx <<-- ECX = p1
movl %eax, (%ecx) <<-- p2->next = p1->next
jmp .L19 <<-- jump to exit
...
.L19
movl %edx, %eax <<-- EAX is always the return value
<<-- return p1->data.
In all of the many calling conventions on x86 the return value of a function is put into the EAX register. (or EAX:EDX if it's an INT64)
In prose: p1 and p2 are pointers to data, in this data pointers to pointers.
This code looks like it manipulates a linked list.
p2->next is set to p1->next.
Other than that the snippet looks incomplete because whatever was in p2->next to begin with is not worked on so there probably more code that you're not showing.
Apart from the confusing AT&T syntax it's really very simple code.
In C the code would look like:
(void *)p2->next = (void *)p1->next;
Note that the code is quite inefficient and no decent compiler (or human) would generate this code.
The following equivalent would make more sense:
mov eax,[ebp+8]
mov ecx,[ebp+12]
mov eax,[eax]
mov [ecx],eax
jmp done
More info on the difference between AT&T and Intel syntax can be found here: http://www.ibm.com/developerworks/linux/library/l-gas-nasm/index.html
I've been tasked with converting IA32 code to Y86. The original program was written in C and is intended to take an array of integers in which the even positioned values call one of three functions and the odd positioned values are operated on within that function. The functions include the negation of a number, the square of a number, and the sum from 1 to the supplied number.
Most of the instructions are easily converted from IA32 to Y86, but there are a number of instructions that are giving me a really hard time.
0000001e <negation>:
1e: 55 push %ebp
1f: 89 e5 mov %esp,%ebp
21: 8b 45 08 mov 0x8(%ebp),%eax
24: f7 d8 neg %eax
26: 5d pop %ebp
27: c3 ret
The neg instruction is not a valid instruction in Y86. This is what I have in Y86:
# int Negation(int x)
Negation:
pushl %ebp
pushl %esi
rrmovl %esp,%ebp
mrmovl 0x8(%ebp),%eax
irmovl %esi,$0
subl %eax, %esi
rrmovl %esi, %eax
popl %esi
popl %ebp
ret
Is this the correct way to go about this problem?
Another instruction is the imul instruction in my square function:
00000028 <square>:
28: 55 push %ebp
29: 89 e5 mov %esp,%ebp
2b: 8b 45 08 mov 0x8(%ebp),%eax
2e: 0f af c0 imul %eax,%eax
31: 5d pop %ebp
32: c3 ret
Does anyone know how the "imul" instruction can be converted in this situation?
Thanks for the help! Any tips on IA32/Y86 Conversion would be greatly appreciated too.
For implementing imul, you might want to look at using a shift and add routine to implement a mul routine:
http://en.wikipedia.org/wiki/Multiplication_algorithm#Peasant_or_binary_multiplication
Then for imul just use the following steps:
figure out what sign the result should have
convert the operands to absolute values (using your negation routine)
call your mul routine on the positive values
convert the result to negative if necessary
1) is mrmovl 0x4(%esp),%eax allowed?
ixorl %eax, 0xffffffff
iaddl %eax, 1
should be slightly more efficient (also ebp can be used as GPR -- no need to push esi)
2) for multiplication there are indeed shift and add-options,
but also a LUT based approach, exploiting the fact that 4*a*b = (a+b)^2 - (a-b)^2.
for each 8x8 bit or NxN bit multiplication.
For a=h<<8+l, B=H<<8|L, aB = Ll + (hL+Hl)<<8 + hH<<16;
could be handled using 3 different tables:
s1[n] = n^2 >>2; s2[n]=n^2 << 6; s3[n]=n^2 << 14;
For negation, you reversed the operands for the irmovl instruction.
The following code works:
#
# Negate a number in %ebx by subtracting it from 0
#
Start:
irmovl $999, %eax // Some random value to prove non-destructiveness
irmovl Stack, %esp // Set the stack
pushl %eax // Preserve
Go:
irmovl $300, %ebx
xorl %eax, %eax
subl %ebx,%eax
rrmovl %eax, %ebx
Finish:
popl %eax // Restore
halt
.pos 0x0100
Stack: