1

I'm corrently working on changing examples from complex indirect addresssing mode into simple indirect addressing mode pieces. However, I've come across an example from the Based Mode, I'm unable to "transform".

Code:

move %eax, 28(%esp)

I've tried

addl    $28, %esp
movl    (%eax), %esp

This creates a segmentation fault; and I've no idea how else I should write it.

Another example, I've failed to "transform is

compl $4, 28(%esp)

-> into

addl    $28, %esp
cmpl    $4, %esp

However this is working, but it changes my output slightly, so it might not be correct as well.

Limon Monte
  • 52,539
  • 45
  • 182
  • 213
Anja Lube
  • 15
  • 2
  • `addl $28, %esp` adds 0x28 (40 in decimal) to the stack pointer. Unless you really know why you are doing with this, this may cause serious problems. A machine interrupt occurring after you have changed the value of `esp` may in the worst case overwrite one or more return addresses of your functions and thus cause `ret` to transfer code flow to whatever address and that may cause segmentation fault. Messing with `esp` without knowing what to do is usually not a good idea. – nrz May 13 '15 at 19:55
  • @nrz: yes it modifies the stack pointer (bad / dangerous), but no, `$28` is just an immediate decimal 28. You'd have to write `add $0x28, %esp` if you wanted hex. In AT&T syntax, immediates always need a leading `$`. `add 28, %esp` would add the dword at absolute address `28` to ESP, a memory source operand with an absolute disp32 addressing mode. – Peter Cordes Jan 07 '19 at 05:06

2 Answers2

1

Example 1:

This:

addl    $28, %esp
movl    (%eax), %esp

doesn't do the same thing as move %eax, 28(%esp). What you're looking for is something like:

addl    $28, %esp
movl    %eax, (%esp)

But note that your version modifies the value of esp, while the original instruction does not.


Example 2:

Again, this:

addl    $28, %esp
cmpl    $4, %esp

doesn't do the same thing as cmpl $4, 28(%esp). The original instruction compares the 32-bit value in memory at address esp+28 with the value 4. Your version compares the value esp+28 with the value 4 (i.e. there's no memory access).

Michael
  • 57,169
  • 9
  • 80
  • 125
  • Thank you for your reply! Well I've tried what you've suggested with switching the brackets, but still hadn't the desired effect. I'm just starting with assembly language and therefore a complete noob, but I guess I've figured it out. – Anja Lube May 13 '15 at 21:40
1

Disclaimer: I am no fan of the AT&T syntax so if the following seems to describe exactly the opposite of what you wanted to do, I messed it up and you need to switch the arguments around (to, from my point of view, the opposite of what the instructions are meant to do, which is then the opposite of what I meant it to but appears to do the other thing ... wait, I think I twisted myself in a corner here).

(Editor's note: yes, this was backwards, e.g. loading instead of storing, and at least one backwards operand other than that. Fixed now.)


mov  %eax, 28(%esp)     # store EAX to memory at ESP+28

You need a scratch register to calculate the store address in. If you were loading, you could calculate in the destination register, but for a store we need the original data and the address. This is one reason addressing modes are so convenient.

mov %esp, %ecx       # copy ESP to ECX
add $28, %ecx        # modify the tmp copy, not the stack pointer
mov %eax, (%ecx)     # store EAX into memory dword pointed to by ECX

As @nrz commented, modifying ESP itself will likely make your function crash later when it tries to return by popping its return address off the stack with ret.


Similarly, a small-steps variant of

cmpl  $4, 28(%esp)

is

mov   %esp, %eax
add   $28, %eax
cmpl  $4, (%eax)     # compare immediate with dword pointed to by EAX

or, if that last line is too complicated (because also indirect),

mov (%eax), %eax
cmp $4, %eax         # dword operand size (cmpl) implied by the register

Note that this instruction sequence alters %eax whereas the original single instruction does not. There is a reason for that: indirect pointer operations are provided because they do not need intermediate registers. (And because they save instructions, increasing the amount of work you can get done per instruction and per byte of code.)

In older CPUs such as the Z80, one indeed had to do indirect addressing by "manually" loading a register as base, adding the offset, then loading the target value.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Jongware
  • 22,200
  • 8
  • 54
  • 100
  • Thank you very much for your reply and your help! It seems to work fine with your changes and makes definitelly more sense then my version. ;) – Anja Lube May 13 '15 at 21:42
  • Your code snippets work just fine in windows, and through the server of the university however, when I try the same "file" out locally in Ubuntu.. it causes a >> Segmentation fault (core dumped)<< Do you maybe know why? – Anja Lube May 14 '15 at 07:30
  • @AnjaLube: Glad to hear I got it right first time! On your follow-up question: I'm afraid I have no idea, there are far too many unknowns here. Try writing a [minimal, complete, and verifiable example](http://stackoverflow.com/help/mcve) and ask as a new question. – Jongware May 14 '15 at 09:04