-2

This question is similar to another question I posted here. I am attempting to write the Assembly version of the following in c/c++:

int x[10];
for (int i = 0; i < 10; i++){
 x[i] = i;
}

Essentially, creating an array storing the values 1 through 9.

My current logic is to create a label that loops up to 10 (calling itself until reaching the end value). In the label, I have placed the instructions to update the array at the current index of iteration. However, after compiling with gcc filename.s and running with ./a.out, the error Segmentation fault: 11 is printed to the console. My code is below:

.data
  x:.fill 10, 4
  index:.int 0
  end:.int 10

.text
.globl _main
_main:
  pushq %rbp
  movq %rsp, %rbp
  subq $16, %rsp
  jmp outer_loop
  leave
  ret

outer_loop:
 movl index(%rip), %eax;
 cmpl end(%rip), %eax
 jge end_loop
 lea x(%rip), %rdi;
 mov index(%rip), %rsi;
 movl index(%rip), %eax;
 movl %eax, (%rdi, %rsi, 4)
 incl index(%rip)
 jmp outer_loop
 leave
 ret

end_loop:
  leave
  ret

Oddly the code below

lea x(%rip), %rdi;
mov index(%rip), %rsi;
movl index(%rip), %eax;
movl %eax, (%rdi, %rsi, 4)

works only if it is not in a label that is called repetitively. Does anyone know how I can implement the code above in a loop, without Segmentation fault: 11 being raised? I am using x86 Assembly on MacOS with GNU GAS syntax compiled with gcc.

Please note that this question is not a duplicate of this question as different Assembly syntax is being used and the scope of the problem is different.

Ajax1234
  • 69,937
  • 8
  • 61
  • 102
  • 1
    I have a dumb question... why not just compile / view the assembly directly rather than writing it yourself? – Ilan Keshet Jul 10 '18 at 18:23
  • 1
    @IlanKeshet That is a possibility, however, I am merely writing the code myself for educational purposes. – Ajax1234 Jul 10 '18 at 18:24
  • 1
    @IlanKeshet : Some people like to do useless stuff for fun - myself included. – Daniel Kamil Kozar Jul 10 '18 at 18:38
  • 1
    **local variables naturally map to registers, not static storage**. You're making life difficult for yourself by bloating your code to keep locals in named static storage locations instead of registers. If you do need to store/reload them (e.g. so you can pass the address of a local to another function), do it on the stack like a compiler. Your asm is like what a compiler would do for `static volatile int i = 0;`. (`volatile` because a compiler will still optimize by keeping it in a register unless you anti-optimize for consistent debugging with GDB, because debug-info doesn't work on regs) – Peter Cordes Jul 11 '18 at 07:46
  • @PeterCordes I did not know about using the stack to store variables. If possible, do you have an example in `x86` `gnu`? Thank you. – Ajax1234 Jul 11 '18 at 15:10
  • @Ajax1234: look at compiler output for a function that does `volatile int foo = 1;`: gcc will either use the red-zone below RSP, or `sub $rsp, 8` / `mov $1, (%rsp)` / `add $8, %rsp` / `ret`. See [How to remove "noise" from GCC/clang assembly output?](https://stackoverflow.com/q/38552116), esp. the link to Matt Godbolt's CppCon 2017 talk. But remember, you don't need to use memory at all when you have lots of registers. Just use comments to keep track of which values are in which registers. – Peter Cordes Jul 11 '18 at 21:50
  • @PeterCordes Thank you very much. That is quite helpful. – Ajax1234 Jul 11 '18 at 21:53
  • Can the downvoter explain how the post can be improved? – Ajax1234 Jul 22 '18 at 19:46

1 Answers1

3

You're using a 64-bit instruction to access a 32-bit area of memory :

mov index(%rip), %rsi;

This results in %rsi being assigned the contents of memory starting from index and ending at end (I'm assuming no alignment, though I don't remember GAS's rules regarding it). Thus, %rsi effectively is assigned the value 0xa00000000 (assuming first iteration of the loop), and executing the following movl %eax, (%rdi, %rsi, 4) results in the CPU trying to access the address that's not mapped by your process.

The solution is to remove the assignment, and replace the line after it with movl index(%rip), %esi. 32-bit operations are guaranteed to always clear out the upper bits of 64-bit registers, so you can then safely use %rsi in the address calculation, as it's going to contain the current index and nothing more.

Your debugger would've told you this, so please do use it next time.

Daniel Kamil Kozar
  • 18,476
  • 5
  • 50
  • 64