-1

I've been looking for hours, and i can't find the mistake in my code. The program seems to exit at the "opadd" tag. I am using x86_64 on Linux, with AT&T syntax.

The program takes as input a string of characters, for example, "2 3 add 4 mul", and then, for this particular example, should do as follows:

  • adds 2 to the stack
  • adds 3 to the stack
  • computes the sum of 2 and 3 and then adds 5 to the stack
  • multiplies 5 and 4 and adds 20 to the stack, and then prints 20.
.data
    formatPrintf: .asciz "%d"
    sir: .space 1000
    delim: .asciz " "
    formatScanf: .asciz "%1000[^\n]"
    cuvant: .space 100
    primulNumar: .space 4
    atoiCuvant: .long 0
    x: .space 4
    y: .space 4
    eval: .long 0
    op: .space 4
    add: .asciz "add"
    sub: .asciz "sub"
    mul: .asciz "mul"
    div: .asciz "div"
.text

.global main

main:
    pushl $sir
    pushl $formatScanf
    call scanf
    popl %ebx
    popl %ebx

    pushl $delim
    pushl $sir
    call strtok
    popl %ebx
    popl %ebx

    pushl %eax
    call atoi
    popl primulNumar

    movl %eax, primulNumar

    pushl primulNumar

et_loop:
    pushl $delim
    pushl $0
    call strtok
    popl %ebx
    popl %ebx

    cmp $0, %eax
    je exit

    mov %eax, cuvant

    pushl %eax
    call atoi
    popl %ebx

    mov %eax, atoiCuvant

    cmp  $0, atoiCuvant
    je operatie

    pushl %eax

    jmp et_loop

operatie:

    push $cuvant
    push $add
    call strcmp
    popl %ebx
    popl %ebx

    cmp $0, %eax
    je opadd

    push $cuvant
    push $sub
    call strcmp
    popl %ebx
    popl %ebx

    cmp $0, %eax
    je opsub

    push $cuvant
    push $mul
    call strcmp
    popl %ebx
    popl %ebx

    cmp $0, %eax
    je opmul

    push $cuvant
    push $div
    call strcmp
    popl %ebx
    popl %ebx

    cmp $0, %eax
    je opdiv

opadd:
    popl %edx
    popl y

    add %edx, y
    push y

    jmp et_loop

opmul:
    popl %eax
    popl %ebx
    mul %ebx
    pushl %eax

    jmp et_loop
opdiv:
    popl %eax
    popl %ebx
    div %ebx
    pushl %eax

    jmp et_loop

opsub:
    popl %eax
    popl y
    sub %eax,y
    pushl y

    jmp et_loop

exit:
    popl eval

    pushl eval
    pushl $formatPrintf
    call printf
    popl %ebx
    popl %ebx

    pushl $0
    call fflush
    popl %ebx

    movl $1, %eax
    xorl %ebx, %ebx
    int $0x80

EDIT:

.data
    formatPrintf: .asciz "%d"
    sir: .space 1000
    delim: .asciz " "
    formatScanf: .asciz "%1000[^\n]"
    cuvant: .space 100
    primulNumar: .space 4
    atoiCuvant: .space 4
    x: .space 4
    y: .long 4
    eval: .space 4
    op: .space 4
    add: .asciz "a"
    sub: .asciz "s"
    mul: .asciz "m"
    div: .asciz "d"
.text

.global main

main:
    pushl $sir
    pushl $formatScanf
    call scanf
    popl %ebx
    popl %ebx
    
    pushl $delim
    pushl $sir
    call strtok
    popl %ebx
    popl %ebx
    
    pushl %eax
    call atoi
    popl %ebx
    
    movl %eax, primulNumar
    
    pushl primulNumar
    
et_loop:
    pushl $delim
    pushl $0
    call strtok
    popl %ebx
    popl %ebx
    
    cmp $0, %eax
    je exit
    
    mov %eax, %esi
    
    pushl %eax
    call atoi
    popl %ebx
    
    cmp  $0, %eax
    je operatie
    
    pushl %eax
    
    jmp et_loop
    
operatie:
    mov $0, %ecx
    movb (%esi,%ecx,1), %al
    
    cmp $97,%al
    je opadd
    
    cmp $115, %al
    je opsub
    
    cmp $109, %al
    je opmul
    
    cmp $100, %al
    je opdiv
    
opadd:
    popl %ebx 
    popl %eax 
    add %ebx, %eax 
    pushl %eax 
    
    jmp et_loop
    
opmul:
    popl %eax
    popl %ebx
        mul %ebx
        pushl %eax
    
    jmp et_loop
opdiv:
    popl %ebx
    popl %eax
    xorl %edx, %edx
    div %ebx
    pushl %eax
    
    jmp et_loop

opsub:
    popl %eax
    popl y
    sub %eax,y
    pushl y
    
    jmp et_loop

exit:
    popl eval
    
    pushl eval
    pushl $formatPrintf
    call printf
    popl %ebx
    popl %ebx
    
    pushl $0
    call fflush
    popl %ebx
    
    movl $1, %eax
    xorl %ebx, %ebx
    int $0x80
Very Nice
  • 29
  • 4
  • Have you tried using a memory checker such as valgrind? Something like that should help you determine what line the problem appeared on. – user1280483 Nov 27 '21 at 19:32
  • @user1280483 thanks, i used gdb, and it seems like the program exits at the "opadd" tag. I still don't know how to solve the problem though – Very Nice Nov 27 '21 at 19:37
  • `opadd` is a *label*. Which *instruction* does it segfault on? – Joseph Sible-Reinstate Monica Nov 27 '21 at 19:39
  • 1
    @JosephSible-ReinstateMonica if i put a breakpoint at ```operatie```, after two ```stepi```, gdb goes to ```??() from /lib32/libc.so.6```, which i think is the ```strcmp```, and after that it terminates with signal SIGSEGV – Very Nice Nov 27 '21 at 20:16
  • This is 32-bit code; I assume you're building it with `gcc -m32 foo.s`. What is going on with all those pushes and pops? You call `strtok` but then you rebalance the stack by popping whatever garbage into EAX, overwriting the return value. Which you then pass to atoi by pushing EAX! Maybe you get lucky and `strtok` didn't happen to overwrite its stack args, and you only do that in the first call, not in the loop, so you get the original string you passed which happens to be the start of the first token? – Peter Cordes Nov 27 '21 at 23:06
  • @PeterCordes i corrected that, but it still gives Segmentation fault error. Do you have any idea why that might be? When i run the program with only numbers, it outputs the last number, which is correct, and when i input only an operator, like "add", it outputs 0, as it should. This error only happens when i input numbers and operators. – Very Nice Nov 28 '21 at 14:09

2 Answers2

0
opadd:
    popl %edx <-- there IS a push without a pop on the first line of code, but...
    popl y <-- now there is nothing left in the stack

It doesn't seem like there is anything left in the stack when you get to opadd. Every push operation in et_loop and operatie has a corresponding pop. I cannot test your example yet, as you didn't include your .data section, but I'm almost sure that this is the problem.

user1280483
  • 470
  • 4
  • 11
  • i added the whole code, but i don't think that is the problem, because the input always starts with 2 numbers – Very Nice Nov 27 '21 at 19:51
  • Have you tried commenting lines out systematically? You'll probably find the problem with one of those `popl` lines. There is no corresponding `pushl` to the `popl y`. – user1280483 Nov 27 '21 at 19:53
  • i don't think that is the problem, because i have tried taking out the pops one by one and nothing changed – Very Nice Nov 27 '21 at 20:13
  • 1
    @user1280483: Mixed in with all the balance push/pop pairs, there is an unbalanced `pushl atoiCuvant` (instead of a simple `push %eax` for some reason), so the querent is probably right that there are two numbers on the stack before `je opadd` is reached. And it is a `jcc`, not a `call`, so it's not popping a return address instead. This might not be a bug. It certainly does look weird, though, but it's possible to simultaneously use the callstack as a stack data structure while also using it to pass args and return address to library functions as long as it cleans up after each such use. – Peter Cordes Nov 27 '21 at 23:15
0
mov %eax, cuvant
pushl %eax
call atoi
popl %ebx

Knowing that atoi espects a pointer, we see that the cuvant variable will hold an address.

operatie:
 push $cuvant
 push $add
 call strcmp
 popl %ebx
 popl %ebx

Knowing that strcmp expects two pointers, we see that this code passes the address of the cuvant variable where in fact it should pass the address that is contained in the cuvant variable (pointing at the current token).
Therefore all comparing in operatie will fail.

 cmp $0, %eax
 je opdiv

opadd:

When all 4 compares fail the code just falls through in opadd:. Nothing good to be expected from that!


For opsub and opdiv the order of the arguments matters. The subtraction does it alright, but the division is wrong.
Consider "8 2 div". The dividend (8) will get pushed first and so has to come off last. And don't forget to zero %edx before using div!

opdiv:
    popl  %ebx            divider (2)
    popl  %eax            dividend (8)
    xorl  %edx, %edx      true dividend %edx:%eax
    div   %ebx
    pushl %eax 
    jmp   et_loop

One drawback of using atoi for dispatching to the operations, is that you won't be able to use the number 0 for an argument (like in "5 0 add"). Should it matter...

Sep Roland
  • 33,889
  • 7
  • 43
  • 76
  • i made all the corrections you suggested, but i still get the Segmentation fault(core dumped) error – Very Nice Nov 29 '21 at 17:39
  • @VeryNice Try the following: `opadd:` `popl %ebx` `popl %eax` `add %ebx, %eax` `pushl %eax` `jmp et_loop`. Also verify if the new code now has `operatie:` `push cuvant` `push $add` `call strcmp`. – Sep Roland Nov 29 '21 at 18:13
  • It still doesn't work – Very Nice Nov 29 '21 at 19:01
  • @VeryNice Consider adding the newest version of your code as an EDIT to your question. Take care to not change anything in the existing question! Write a new EDIT section beneath what is already there. – Sep Roland Nov 29 '21 at 20:06
  • I added the EDIT section – Very Nice Nov 29 '21 at 20:21