0

I have a task like this: Implement the function with the signature in x86-64 assembly language:

extern int * A;
extern void func(size_t N);

The function in the loop N times:

  1. Enters a signed 32-bit integer from the keyboard;
  2. Multiplies it by the current array element A;

At the end prints the result to the screen. I wrote this program:

.intel_syntax noprefix
.text
.global func
.global A

func:

    sub rsp, 16
        mov r8, 0    // r8 = sum = 0
    mov r9, rdi  // r9 -> N
    
loop:
    cmp r9, 0
    je end
    sub r9, 1
    
    mov rdi, scan_format
    mov rsi, var1
    call scanf
    
    mov rsi, var1
    mov rsi, [rsi]
    
    mov rcx, A
    
    mul rcx
    add r8, rcx
    jmp loop
    
end:
    mov    rdi, print_format
    mov    rsi, r8
    call printf

    add sp, 16
    ret
    
.data
var1:
    .word 0

scan_format:
    .string "%d"

print_format:
    .string "%d\n"

but I get a segmentation fault and don't understand why?

1201ProgramAlarm
  • 32,384
  • 7
  • 42
  • 56
AshGi
  • 13
  • 3
  • Possibly stack alignment. Subtract 24 from rsp instead of 16. – prl Nov 09 '21 at 20:42
  • Also, `add sp, 16` should be `add rsp, 16`, and unless I'm mistaken result of `mul rcx` goes to `edx:eax`, not `ecx`. Also, it's not entirely clear to me what `var1` is, but do you really mean to do double indirection through `rsi`? – 500 - Internal Server Error Nov 09 '21 at 20:43
  • Scanf %d format requires the address of a long, not a word. – prl Nov 09 '21 at 20:45
  • 1
    When reading var1 into rsi, it reads a qword, but var1 is a word. – prl Nov 09 '21 at 20:46
  • @500, the first move into rsi gets the address of var1. (Depending on the assembler, but if not, it is also incorrect in many other places.) – prl Nov 09 '21 at 20:48
  • @prl yes at the end there should be add rsp, 16. For the rest of the comments that you made, I'll think about it. I am a beginner and not all your words are still clear to me. – AshGi Nov 09 '21 at 20:55
  • The x86-64 ABI (which defines the interface between the application and the library, among other things) requires the stack to be 16-byte aligned before a call. Since the call itself pushes the 8-byte return address on the stack, at the entrance to the function, the stack is misaligned. To align it again to a 16-byte boundary, every function must subtract an *odd* multiple of 8 from rsp to realign it before calling another function. – prl Nov 09 '21 at 21:41
  • 1
    Since you don't need widening multiplication, two-operand `imul` works just as well and is more convenient than `mul` with its hardcoded registers. – Nate Eldredge Nov 09 '21 at 22:34
  • The segfault is [glibc scanf Segmentation faults when called from a function that doesn't align RSP](https://stackoverflow.com/q/51070716). Other bugs are separate, like wrong use of `mul` instead of `imul ecx, esi` or something, and using 64-bit operand-size on `int` data. And missing a level of indirection in `mov rsi, [rip + A]` ; `mov esi, [rsi]` or something. Once you have it not segfaulting, you'll be able to use a debugger and single-step your code to find the other bugs. – Peter Cordes Nov 10 '21 at 00:56

0 Answers0