0

I am learning assembly NASM and trying to do a LFSR code and call it on a C program to evaluate the execution time diference, but failed to figure out the problem with my code.

My LFSR C version works just fine and is defined as follows:

int lfsr(){
    int cont = 0;
    uint32_t start_state = SEED;
    uint32_t lfsr = start_state;
    uint32_t bit;

    while (cont != 16777216) {
      bit  = ((lfsr >> 1) ^ (lfsr >> 5) ^ (lfsr >> 7) ^ (lfsr >> 13)) & 1;
      lfsr = (lfsr >> 1) | (bit << 23);
      lfsr_nums[cont] = lfsr;
      cont++;
    }

    return cont;
}

My NASM x86 was based on the C version and it generates the numbers the same way the C code does. It should take a pointer to an array as parameter, and return (as reference) the same array with the numbers created and return (as value) the amount of the numbers. The LFSR logic works just fine, I checked the numbers created, but the code still give me a SegFault Core Dump error.

With gdb the message is that the error is in the do procedure. While I tried to debug my code I found out that the error was in the mov dword [esi + 4 * eax], ebx, if I comment it out the code doesn't output a segfault.

section .text
global lfsr_nasm

lfsr_nasm:
    push dword ebx;
    mov esi, edi ; vec
    mov eax, 0 ;Cont = 0
    mov ebx, 0x1313 ; lfst = start_state = seed
    do:
        mov ecx, ebx ; ecx = lfst
        shr ecx, 1 ; lfsr >> 1
        mov edx, ebx ; edx = lfst
        shr edx, 5; lfst >> 5
        xor ecx, edx ; lfst >> 1 ^ lfsr >> 5
        mov edx, ebx ; edx = lfsr
        shr edx, 7 ; edx = lfst >> 7
        xor ecx, edx; lfst >> 1 ^ lfsr >> 5 ^ lfsr >> 7
        mov edx, ebx ; edx = lfsr
        shr edx, 13 ; edx = lfst >> 13
        xor ecx, edx; lfst >> 1 ^ lfsr >> 5 ^ lfsr >> 7 ^ lfsr >> 13
        and ecx, 1 ;ecx = bit
        shr ebx, 1 ;lfsr >> 1
        shl ecx, 23 ; bit << 23
        or ebx, ecx ; lfsr = (lfsr >> 1) | (bit << 23);
        mov dword [esi + 4 * eax], ebx
        inc eax ; cont++
        cmp eax, 16777216; cont != 16777216
        jne do ;
    pop dword ebx;
    ret

The way I make the call in C, and declare my vector and NASM function:

extern int lfsr_nasm (uint32_t *vec);
uint32_t lfsr_nums[16777216];

int main(int argc, char *argv[]){
    int cont;
    cont = lfsr_nasm(lfsr_nums);
    for(int i = 0; i < 16777216; i++){
       printf("%d ", lfsr_nums[i]);
    }
}

I believe that the vector is too big for the NASM or C and maybe the program is trying to access bad memory, but I couldn't find anything to confirm my believes neither a fix to the problem. Already tried with malloc and calloc.

Skalwalker
  • 299
  • 3
  • 23
  • 2
    How about using `0x1000000` instead of `16777216`. Doesn't change result but makes clear magic number is base-2. – Fiddling Bits Nov 18 '19 at 21:50
  • You're writing 32-bit code, not 64-bit, so args are passed on the stack, not in RDI, RSI, RDX, ... Also, EDI and ESI are call-preserved. If you want to write 64-bit code, `push/pop` RBX, and use 64-bit registers for your pointers. Look at compiler-generated code to see how its passing args. – Peter Cordes Nov 18 '19 at 22:21
  • I want to write 32-bit code – Skalwalker Nov 18 '19 at 22:32
  • Then args are passed on the stack, and EDI + ESI are call-preserved. Use a pointer increment so you can just keep a pointer in EAX instead of needing base + index registers. e.g. like GCC makes: https://godbolt.org/z/uedzZz – Peter Cordes Nov 18 '19 at 22:47

0 Answers0