Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling an assembly function from C

Tags:

c

assembly

x86-64

One of my generated functions doesn't compute what it should and I am trying to debug it separately. I have the assembler for it and I try to call it from a stripped down C program. However, for some reason I end up getting segfaults in the function (so, calling the function seems to work, but execution fails). There might be something wrong with passing the arguments..

The functions signature is

void func(int, int, float*, float*, float*);

The function ignores the first two arguments and received 3 arrays of 32 floats each. It would add element-wise the latter two and store the result element-wise into the first array. However, it would do that in a kind of weird order (as opposed to streaming linearly through it, the reason for doing this is not in the scope of this SO question). That's what the offset_arrays are for in the assembler code.

I checked the x86 calling conventions (that's the architecture I am using) and the first six integer or pointer arguments are passed in registers RDI, RSI, RDX, RCX, R8, and R9.

Here' the function implementation:

    .text
    .globl  func
    .align  16, 0x90
    .type   func,@function
func:
    .cfi_startproc
    xorl    %eax, %eax
    movabsq $offset_array1, %r9
    movabsq $offset_array, %r10
    xorl    %esi, %esi
    .align  16, 0x90
.LBB0_1:
    movq    (%r9,%rax), %r11
    movq    (%r10,%rax), %rdi
    movss   (%r8,%rdi,4), %xmm0
    addss   (%rcx,%rdi,4), %xmm0
    movss   %xmm0, (%rdx,%r11,4)
    incq    %rsi
    addq    $8, %rax
    cmpq    $33, %rsi
    jb  .LBB0_1
    retq
.Ltmp0:
    .size   func, .Ltmp0-func
    .cfi_endproc

    .type   offset_array,@object
    .section    .rodata,"a",@progbits
    .align  16
offset_array:
    .quad   0
    .quad   16
    .quad   1
    .quad   17
    .quad   2
    .quad   18
    .quad   3
    .quad   19
    .quad   4
    .quad   20
    .quad   5
    .quad   21
    .quad   6
    .quad   22
    .quad   7
    .quad   23
    .quad   8
    .quad   24
    .quad   9
    .quad   25
    .quad   10
    .quad   26
    .quad   11
    .quad   27
    .quad   12
    .quad   28
    .quad   13
    .quad   29
    .quad   14
    .quad   30
    .quad   15
    .quad   31
    .size   offset_array, 256

    .type   offset_array1,@object
    .align  16
offset_array1:
    .quad   0
    .quad   16
    .quad   1
    .quad   17
    .quad   2
    .quad   18
    .quad   3
    .quad   19
    .quad   4
    .quad   20
    .quad   5
    .quad   21
    .quad   6
    .quad   22
    .quad   7
    .quad   23
    .quad   8
    .quad   24
    .quad   9
    .quad   25
    .quad   10
    .quad   26
    .quad   11
    .quad   27
    .quad   12
    .quad   28
    .quad   13
    .quad   29
    .quad   14
    .quad   30
    .quad   15
    .quad   31
    .size   offset_array1, 256


    .section    ".note.GNU-stack","",@progbits

I try to call the function from this C code:

float f0[32];
float f1[32];
float f2[32];

extern void func(int i0,int i1,float* dest,float* src0,float* src1);

int main(int argc, char *argv[])
{
  func(0,0,f0,f1,f2);
}

Compiling both and linking with

gcc -o f.o -c -g f.S
gcc -g -o test_f test_f.c f.o

and running though gdb results in

Program received signal SIGSEGV, Segmentation fault.
func () at f.S:17
17      movss   %xmm0, (%rdx,%r11,4)

So, this is obviously a write to memory, namely to the first array. Why would it segfault and how to call this function correctly (without changing the assembler code)?

like image 351
ritter Avatar asked Sep 12 '26 15:09

ritter


1 Answers

The problem comes from this line

cmpq    $33, %rsi

it should be

cmpq    $32, %rsi

you are accessing the junk in the memory after .quad 31 and sticking that into r11 at movq (%r9,%rax), %r11

like image 182
merridius Avatar answered Sep 15 '26 07:09

merridius