0
%include "asm_io.inc"

segment .data

segment .bss

segment .text
    global secret_func
secret_func:
    enter 0,0
    push ebx

    cmp     ebx, 1
    jne     while_init
    jmp     case_one

while_init:
    mov     ecx, 2          

while:
    cmp     ecx, ebx 
    jge     case_two           

    xor     edx, edx        
    mov     eax, ebx        
    div     ecx             

    cmp     edx, 0          
    je      case_one

    add     ecx, 1
    jmp     while  

case_one:
    mov     eax, 0
    jmp     end

case_two:
    mov     eax, 1

end:
    mov ebx, eax
    pop ebx
    mov eax,0
    leave
    ret

given the above secret.asm, which as far as i understand it checks if a given int value is prime or not. or?

#include <stdio.h>

extern int secret_func (int);


int main()
{
    int ret_status;
    ret_status = secret_func(3);
    printf("%i\n",ret_status);
    return 0;
}

and the above main.c which is supposed to call the assembly function with the value 3 and then print the assembly functions return value.

im trying to compile and link these 2 files with (using asm_io from paul carters set):

nasm -f elf -o secret.o secret.asm
nasm -f elf -d ELF_TYPE -o asm_io.o asm_io.asm 
gcc -m32 -c -o main.o main.c -std=c99 -Wall
gcc -m32 -o secret -std=c99 -Wall main.o secret.o asm_io.o

I am not sure where my mistake is, did i understand the assembly program correctly or is there a mistake while linking or compiling?

tamut
  • 61
  • 10
  • What error are you getting? is it a compile or runtime error? – Martín Zaragoza Aug 17 '18 at 20:02
  • What errors do you get when trying to compile/link? – dbush Aug 17 '18 at 20:03
  • it always prints 0 which in turn must be the return value of secret_func() with the value 3... No mater which number I call it with though, it always returns 0. – tamut Aug 17 '18 at 20:04
  • I'm not sure there's anything wrong with your C code or your build procedure. My x86 assembly knowledge is a bit rusty, but it looks like the assembly code always returns 0. – Fred Larson Aug 17 '18 at 20:07
  • thats correct and i dont understand why – tamut Aug 17 '18 at 20:21
  • 3
    I don't think that asm code is correct, it always returns 0 and it seems to read its input from EBX which is not a C calling convention I'm familiar with. Mainly the "case_two" seems broken, since the 1 it writes in eax is overwritten before returning, – PeterT Aug 17 '18 at 20:22
  • maybe add `mov ebx, ecx` after `push ebx` and remove the `mov eax,0` before the `leave` – PeterT Aug 17 '18 at 20:26
  • What operating system and architecture are you programming on? – fuz Aug 17 '18 at 22:05

1 Answers1

0

This worked for me. The only two lines changed are:

1) the argument being read from the stack into ebx where this function expects the argument.

2) don't overwrite EAX with 0 immediately before returning. The only way to reach end is via case_one or case_two and those already set the return value.

%include "asm_io.inc"

segment .data

segment .bss

segment .text
    global secret_func
secret_func:
    enter 0,0
    push ebx
    mov     ebx, [ebp + 8] ; first argument by gcc x86 calling convention
    cmp     ebx, 1
    jne     while_init
    jmp     case_one

while_init:
    mov     ecx, 2

while:
    cmp     ecx, ebx
    jge     case_two

    xor     edx, edx
    mov     eax, ebx
    div     ecx

    cmp     edx, 0
    je      case_one

    add     ecx, 1
    jmp     while

case_one:
    mov     eax, 0
    jmp     end

case_two:
    mov     eax, 1

end:
    mov ebx, eax
    pop ebx

    leave
    ret
PeterT
  • 7,981
  • 1
  • 26
  • 34
  • `enter` is very slow; there's a reason gcc never uses it even when making a stack frame. `leave` is not bad, though. I suggest looking at `gcc -O3 -m32` output for a C version of your function. ([How to remove "noise" from GCC/clang assembly output?](https://stackoverflow.com/q/38552116)). And see [C++ code for testing the Collatz conjecture faster than hand-written assembly - why?](https://stackoverflow.com/q/40354978) for more about why you should right shift by 1 instead of `div` by 2. And [Why are loops always compiled into "do...while" style?](https://stackoverflow.com/q/47783926) – Peter Cordes Aug 18 '18 at 03:11
  • 1
    @PeterCordes those are good hints. But I hope the OP didn't choose asm for performance in this case. Because a better algorithm for finding primes will speed this up by orders of magnitude.Regardless of whether C or asm is used. – PeterT Aug 18 '18 at 06:51
  • Oh right, I missed that `ecx` was being incremented. The meaningless `case_one` and `case_two` label names, and lack of comments, didn't make it obvious from a quick look what this code was going. `div` is reasonable for a naive trial-division implementation, so the major optimization here is algorithmic, not implementation. But there are lots of basic ways this code could be more smaller and more efficient in ways that would matter when implementing other loops that don't just bottleneck on `div`. – Peter Cordes Aug 18 '18 at 07:02
  • very nice, yes I forgot to get the first argument from the stack and write it to ebx through [ebp+8] and that was why i always got the zero returned from the function. now it works as it is supposed to and returns either 1 or 0 depending prime or non prime number – tamut Aug 18 '18 at 17:58