1

The lea instruction ("load effective address") takes the memory address of the first value and adds it to the second value - which may be multiplied. It then loads that memory address into a given register.

Let me make an example to clarify my confusion:

eax = 2
leal (%eax, %eax, 4), %edx

I believe the result of this is that edx will have the value 10 inside of it (2 + 2 * 4 == 10). But why is this instruction for memory addresses if it's just doing arithmetic on integers?

I have read other responses, but they all talk about memory addresses being the only thing involved. Can someone help me understand what leal is doing?

Michael Petch
  • 46,082
  • 8
  • 107
  • 198
  • 1
    no it's not a duplicate. I specifically referenced that I had read that and was still confused. – Adam Reb Alloy Mar 23 '15 at 04:05
  • I have been using leals for a while too, and it seems like the destination register holds a memory address that points to the sum of the base register, the multiplier, and the index. but when I read explanations it seems like it just holds a memory address that ITSELF is the sum of those three memory addresses. – Adam Reb Alloy Mar 23 '15 at 04:07
  • Closer: This guy is asking a good question. It took "us experts" awhile to understand his confusion. THATS NOT A PROBLEM WITH THE QUESTION. – Ira Baxter Mar 23 '15 at 05:00
  • the updated title is much better – phuclv Mar 23 '15 at 07:52
  • 1
    In early x86 designs, LEA was implemented by the AGU (Address Generation Unit). A separate logical circuit from the ALU. Compiler writers took advantage of it, a way to get a simple addition and shift that runs concurrently with another instruction that uses the ALU. A very early form of super-scalar execution before that became a built-in feature of cores. It is not relevant anymore. – Hans Passant Mar 23 '15 at 09:07
  • Note that the instruction, leal (%eax, %eax, 4), %edx, has the same addressing mode as movl (%eax, %eax, 4), %edx, the difference is that leal puts the computed address in edx, while the movl puts the 32 bit content at that address into edx. (Assuming that the address is a legal address and doesn't cause a memory access error.) – rcgldr Mar 23 '15 at 16:54
  • @MichaelPetch: See [Creating tags for single-assembly instructions?](//meta.stackoverflow.com/q/366109) on meta. Let's leave the x86-lea and x86-test tags alone for now until the dust settles. – Peter Cordes Apr 17 '18 at 02:06
  • @PeterCordes : I have already responded there. I'm going to do what I intended last night to just make the process official and see one way or another whether a burniate request for x86-cmp, x86-lea, and x86-test should occur. I'll accept the results of that specific dialogue which ever way it goes. The number of answers with these tags was very limited. Didn't take long to remove them. If they don't get burniated then I accept their future usage if that is the will of SO. – Michael Petch Apr 17 '18 at 02:07

3 Answers3

3

It is named for its purpose.

Most instructions include the same addressing modes. The CPU architects call the work of determining the memory address selected by the addressing modes as "computing the effective address".

The instruction purpose is to put the effective address into a register. Hence, "load effective address".

Yes, it is true "it just performs arithmetic". If you think about it, that's pretty much all a CPU does, so that phrase isn't very descriptive of any particular instruction or CPU activity.

If you want to understand how many instructions get their names (let alone what the purpose of an instruction is), it is a good idea to take a computer architecture class.

[Edit after long comment interaction, below]:

Most of the answers here (including mine) were hung up on "computing effective addresses", in which the instruction is used to form a memory address, where the instruction has a well-deserved name.

However, since the instruction doesn't actually use the computed "address", another extremely common use of the LEA instruction is simply do the arithmetic that it does. In effect, LEA viewed from this perspective is a combination of compute sums or products with some special small constants, and store the result to another register without affecting the condition bits. It also happens to do this very quickly compared to doing a real multiply. The utility of this in real programs is surprisingly high; get some experience writing assembly code on x86 and you will believe this.

So LEA can be used, for example, to multiply a register by 5 and add a big constant. Here the instruction name only confuses; unfortunately, it still has to have a name.

Welcome to assembly-code land, where designers invent instructions to achieve one purpose, and coders discover that they can use the instruction to compute things the designers didn't obviously consider. [The AND-immediate instruction is pretty handy for computing modulo some-power-of-two, as another example]. So every instruction in a rational instruction set was placed there by the instruction architect becuase it serves some useful purpose. And it gets use for that, and other things, as coders discover clever applications.

Ira Baxter
  • 93,541
  • 22
  • 172
  • 341
  • 1
    dude I am in a computer architecture class. I know that it puts an effective address into a register - my question is whether that effective address points at a value which computed based on parameters of the lea or whether the memory address held in the register is computed by adding other memory addresses. way to not answer anything and talk down to me your entire response, asking for help is embarassing enough. – Adam Reb Alloy Mar 23 '15 at 04:11
  • my problem is everyone uses the term effective address but I do not have a clear understanding of what that term means - effective address sounds like the address itself is what the instruction computes, not the value at the address. – Adam Reb Alloy Mar 23 '15 at 04:12
  • If you're going to get huffy, you're not going to get any help. Sorry if I cannot read your mind to understand your problem; you were pretty clear I thought with the bold face font in you question, and that's what I answered. Regarding your question in this comment: if you had any other machine instruction X with the same addressing mode (register names, contents, offsets), that instruction X would compute an effective address according the rules of the architecture. (You can read about x86 addresssing modes on your own for details). LEA computes the effective address. – Ira Baxter Mar 23 '15 at 04:16
  • I do appreciate that you are trying to help, and I am not phrasing my question well because I lack the syntax to. I clearly said I don't understand what the term effective address refers to - then you continued to explain to me what I am trying to understand using that term. – Adam Reb Alloy Mar 23 '15 at 04:20
  • Yes, the effective address is the address computed by the addressing mode information, not the value at the address. Make sure you tell the prof that this confused you, it will help him make sure the message is clear to the class. No foul here, machine architectures are pretty confusing on first encounter. – Ira Baxter Mar 23 '15 at 04:20
  • so what is the value at the effective address? – Adam Reb Alloy Mar 23 '15 at 04:22
  • PS: The only stupid question is the one you didn't ask :-} – Ira Baxter Mar 23 '15 at 04:22
  • So the effective address is a location in memory. Depending on the instruction (exp. x86), that may mean a byte, 2bytes ("DWORD"), 4bytes ("QWORD") or even some other size. What happens to the memory at that address depends on the instruction; some instructions are defined to read the memory at EA, some to modify the memory at EA. The LEA instruction very carefully does neither one... so what's the point? One answer is that this address will be needed by another piece of code, that does not expect of have access to the registers at the point the LEA is executed. – Ira Baxter Mar 23 '15 at 04:25
  • 1
    I assume you are familiar with "C"? LEA is the machine equivalent of "&texp" (take the address of texp). – Ira Baxter Mar 23 '15 at 04:27
  • thank you so much. here is what is really confusing me. leal (%edx, %edx,2), %eax sall $4, %eax my professor said those statements have this behavior eax = 3y (to me it seems like that is edx = y, so eax = edx + 2 edx. then the shift, by 4, means that value is being multipled by 16. the end result of the two instructions is eax = 48y. but, my understanding of lea which I think you just confirmed, is that I have loaded the effective address of 3 edx into eax, which should not contain the value of 3 edx but it's EA, so why is the value y at edx being multiplied by 3? – Adam Reb Alloy Mar 23 '15 at 04:33
  • 2
    Your confusion seems to about the size of memory operands, and why effective address computation can apparently multiply by (on the x86, get this: 1, 2, 3, 4, 5, 8, and 9). So, the first issue is that every memory operand has a size, S, in bytes. Often, we place these operands in linear arrays in memory, and want to fetch the kth entry in an array at address A. To find the address of the kth entry, you need to multiply S by k Now, you technically don't need all that effective address computing machinery; you could simply write machine instructions that computed the array element yourself – Ira Baxter Mar 23 '15 at 04:38
  • 2
    ... easily enough: mov edx, k; mul edx, S; add edx, A. This would give the address of the kth element in edx. This is so common, that the CPU architects put addressing modes into the chip that do all this for certain common values of S (that weird list I gave, yes it works pretty well). So instead we can write: mov edx, k; lea edx, A[S*edx] for common value of S. .... – Ira Baxter Mar 23 '15 at 04:44
  • 2
    Now, I think I begin to see your problem: LEA is normally used to compute addresses of data in memory. BUT... it does handy arithmetic that other arithmetic instructions don't do. Since it doesn't actually *use* the address, it can be "abused" to simply do the arithmetic. If you want to multiply a value by 9, you can use LEA to do it. In this case, the instruction is no longer being used according to its named purpose... it is being used because it happens to do a useful thing. On x86 machines, this is really handy, so you see LEA used for this. And yes, it is "just" arithmetic. – Ira Baxter Mar 23 '15 at 04:46
  • The reason for using LEA for this purpose (rather than a real multiply or shift) is that it is *fast* because it is an intrinsic part of the execution of each instruction, *and* it happens to include what amounts to a register move, too boot. Write enough assembly code, this will become pretty obvious. – Ira Baxter Mar 23 '15 at 04:48
  • thank you so much for spending the time to explain all of that. the first two comments, I think I understand, memory is theoretically like a giant array. lea works like a fancy move: it computes the EA based on the size of the operand, the initial address, and k. I still don't understand why, in this particular case, lea is mutliplying the edx value by 3 - but I emailed my professor so he'll explain it. thanks so much, you have definitely clarified a lot. my professor has used 3 different assembly languages in one unit so it's hard to keep track if things work differently on x86 vs y86. – Adam Reb Alloy Mar 23 '15 at 04:56
  • Obviously, LEA doesn't multiply by lots of interesting constants. When you run in to that, you get to fall back to the conventional machine instructions for shifting and multiplication. Not very well know: with the right sequence of just a few LEA, SHL, MOV, ADD and SUB instructions, you can multiply by an amazing variety of constants. MUL instructions now are very fast but still take a few cycles; they use to take LOTS of cycles and people would do all sorts of stuff to avoid doing a multiply if possible. Exercise for student: Use two successive LEAs to multiply a register by 63. – Ira Baxter Mar 23 '15 at 04:57
  • .. multiply by 3: the addressing mode given in your example is essentially 1*EDX+2*EDX --> 3*EDX. Easy. – Ira Baxter Mar 23 '15 at 04:59
  • yeah I think I get it now. the value in the register was the effective memory address and, since it's in a register it is treated like a value. then we shift that, so the end result is 48*the memory address of edx. – Adam Reb Alloy Mar 23 '15 at 05:01
  • and I am going to try that 2 lea problem because I have a test on wednesday I am studying for. – Adam Reb Alloy Mar 23 '15 at 05:01
  • Oh, sorry, I goofed (can't do simple math anymore). You can't get two succesive LEAs to compute multiply by 63 (convincing yourself of this is exercise number 2). You can get two successive LEAs to multiply by 45. – Ira Baxter Mar 23 '15 at 05:05
  • Good luck with your test. – Ira Baxter Mar 23 '15 at 05:05
  • Sigh. One more clarification: your example is actually "leal (%eax, %eax, 4), %edx". I'm reading that as "1*eax+4*eax" or 5*eax. I don't know how 3 got into this discussion. – Ira Baxter Mar 23 '15 at 05:11
  • I always alter anything I post on here so I understand how it is actually working instead of how it works in a particular instance, so I changed up some of the values haha - I just picked random numbers but I kept talking like I had used the same numbers. – Adam Reb Alloy Mar 23 '15 at 05:15
  • If you like any of the answers/comments to your question, you should upvote the answer. (You made me work for this one!) – Ira Baxter Mar 23 '15 at 08:37
3

The reason why the LEA works the way it does is because on the original 8086 the LEA instruction reused the processor's effective address calculation hardware. The effective address hardware calculates the address the memory operand of an instruction acts on. Since there a number of different basic operations that need to be performed to calculate an effective address, this means there was relatively speaking a lot of power packed into a LEA instruction. Most "real" arithmetic instructions only performed one operation at a time, and most require that destination register be one of the source operands. Since it could be implemented a tiny amount additional encoding space and silicon area, it was pretty cheap considering what its capable of doing.

So an instruction like MOV AX,[BX + SI] (I'm using Intel syntax here) loads AX with the 16-bit value stored at the address calculated by adding BX and SI . The instruction LEA AX,[BX + SI] loads AX with the address calculated by adding BX and SI. In other words the LEA instruction treats memory operands differently than other instructions. Instead operating on the memory at the address indicated by the memory operand, it uses the calculated address directly as the operand. The same address encoding is used for both instruction, the LEA instruction just tweaks how the memory operand is interpreted.

In other words, LEA is called that because that's exactly what it does. It loads the effective address given by a memory operand into the destination register. Since the memory operand isn't actually used as memory operand, it does in fact work like an ordinary arithmetic instruction. If ADD is the addition arithmetic instruction, then LEA is the effective address arithmetic instruction.

Ross Ridge
  • 38,414
  • 7
  • 81
  • 112
  • thank you, I really liked that explanation. I just explained to ira, who is awesome, that I have confusion about why this is happening leal (%edx, %edx,2), %eax # eax = y*3 sall $4, %eax # eax *= 16(eax) # eax = 16*3 = 48y – Adam Reb Alloy Mar 23 '15 at 04:35
  • if eax contains an effective memory address, and not a value that is (%edx)+(%edx)+(%edx), then why does the value at the end of those operations 16*3 instead of just 16*whatever is at the EA – Adam Reb Alloy Mar 23 '15 at 04:37
  • @Adam You should ask separate question about that. I have hard time understanding what that code is when it's all jammed together like that in comment. All I can say is that kind of arithmetic calculation is possible with LEA , and not that unusual. – Ross Ridge Mar 23 '15 at 04:40
  • @AdamRebAlloy A register isn't an effective address, and once an EA is loaded into a register using LEA it's no longer an EA, it's just a value like any another arithmetic result. Only memory operands have effective address. – Ross Ridge Mar 23 '15 at 04:44
  • ok, so it is changing the memory address, and that memory address happens to be 3 times higher than the initial value. – Adam Reb Alloy Mar 23 '15 at 04:57
  • @Adam Your example code doesn't seem to be calculating an address so it wouldn't be changing an address. While the LEA instruction performs the same arithmetic operations the processor uses to calculate an effective addresses, it doesn't mean that you can only calculate addresses with it. The effective address calculation is just a complicated arithmetic calculation. Since the LEA instruction doesn't touch memory, the result doesn't have to be a valid or meaningful address. – Ross Ridge Mar 23 '15 at 05:12
  • @AdamRebAlloy put codes into backticks `likethis`, otherwise it'll be very difficult to read – phuclv Mar 23 '15 at 06:46
  • 1
    It's also worth pointing out that `LEA` doesn't affect the flags register - which is often very useful., e.g., arithmetic inside a loop. – Brett Hale Mar 23 '15 at 09:13
0

The simple answer for why lea references the concept of effective addresses in its name is that it is intended for calculating effective addresses. Names and intentions often go together (although I wish they did more often - there are endless examples of unnecessarily obscure terminology in this field).

Perhaps the problems people often have understanding the purpose of lea have more to do with the term 'load'. 'Load' suggests that a memory operation is performed, although it is not. This is even more likely to be confusing because there is a conceptual association between effective addresses and memory. Finally, the syntax of the memory operand to lea is that of a operand that in other instructions denotes an actual load. Given all this, some initial confusion over whether or not lea produces a memory access is understandable.

Perhaps a better mnemonic would have been cea, 'calculate effective address'. Oh well.

gsg
  • 9,167
  • 1
  • 21
  • 23
  • I think it's likely that LEA was designed to expose that hardware functionality (decoding ModR/M + disp0/8/16, and doing the actual calculation) for purposes including integer copy+add of values including by not limited to actual addresses. The name describes what it does, but the way I think about it, doesn't imply that it's intended only for integer values that currently or ever happen to be valid addresses. Whether or not that's what the designer intended, looking at it this way makes it make sense (including current uses). Agreed that `cea` would have been a good choice. – Peter Cordes Mar 30 '18 at 00:39