2

I don't know why my program doesn't show the result of the sum of elements in the stuck. It just shows the string '-----'

I'm working on Linux.

.data 
#################################
tabEntier :   .long 3, 4, 2, 10, 16, 5, 6   #long = 4                     
maVar:  .space 4             

msgFin: .string "\n-----\n"
taillemsgFin = . - msgFin

################################
.text

.global _start 

_start:
movl $3, %eax          # eax ?
movl $0, %ebx          # ebx ?
movl $tabEntier, %ecx  # ecx ?

additionne:   
addl (%ecx), %ebx   # ebx  ?
    addl $4, %ecx       # ecx ?
    decl %eax           # eax ?
    jnz additionne       

stocke:
movl %ebx, maVar     

messageSortie:

movl $4, %eax        
movl $1, %ebx        
movl $msgFin,%ecx    
movl $taillemsgFin,%edx  
int $0x80        

sortie:  
movl $0, %ebx        
movl $1, %eax        
int $0x80      

The result of the sum must be shown after '------' message

phuclv
  • 37,963
  • 15
  • 156
  • 475
JSecurity
  • 85
  • 1
  • 9
  • 4
    Why would it show anything else? You have not written any code to do so. You will need to convert the result to text and print it. If you are allowed to use libc then call `printf`. – Jester Oct 31 '18 at 00:25

1 Answers1

4

I don't know why my program don't show the result of the sum

It's because you don't actually have any code for outputting that. You syscall-4 to output the ---- string, then you immediately syscall-1 to exit.

If you want to output an integral value as well, you're going to need some code to do it. While modern CPUs have speculative execution, that doesn't mean speculating on what you really wanted to do :-)

You may also want to check what you're loading into eax. This seems to be the count of elements and there are seven in the list, but you only process the first three. No doubt you would have found that once you'd successfully output the sum but I thought I'd mention it anyway.


In terms of the code required to fix your issue, I include a small utility function for printing of signed longs, along with a test harness so that you can see it in action.

The test harness is a simple bash script which processes a series of test data items, injecting them in turn into the actual test program:

#!/bin/bash

# Selected test points, and some random ones.

testdata="0 1 -1 9 10 -9 -10 99 100 2147483647 -2147483648"
for i in {1..10} ; do
    testdata="${testdata} ${RANDOM} $((0 - ${RANDOM}))"
done

# Do each test item.

for item in ${testdata} ; do
    # Morph the asm template to create actual asm file,
    # then assemble and link.

    sed "s/XYZZY/${item}/" prog.in >prog.asm
    as --32 -o prog.o prog.asm
    ld -melf_i386 -o prog prog.o

    # Test that output is as expected.

    result="$(./prog)"
    if [[ "${item}" == "${result}" ]] ; then
        echo "Okay ('${item}')"
    else
        echo "BAD  ('${item}' -> '${result}'"
    fi
done

The code for testing this is in a template prog.in so it can be processed by that test harness to produce one with the actual test item. The file contains:

.data

numOut:     .string "2147483648"    # Largest signed-32 magnitude.
numEnd:
numLast=    numEnd - 1

negOut:     .string "-"             # Negative prefix.

# ======================================================================
# Actual function for output of signed long in EAX.

.text

outLong:    push    %eax            # Save registers.
            push    %ebx
            push    %ecx
            push    %edx

            cmpl    $0, %eax
            je      olZero          # Zero special case.

            jg      olPos           # Already positive.

            push    %eax            # Negative handled here.
            movl    $4, %eax        # SysWrite "-".
            movl    $1, %ebx
            movl    $negOut, %ecx
            movl    $1, %edx
            int     $0x80
            pop     %eax
            negl    %eax            # Then negate.

olPos:      movl    $numEnd, %ecx   # Last character placed.

olStore:    movl    $0, %edx        # eax = edx:eax / 10, remainder -> edx
            movl    $10, %ebx
            divl    %ebx

            addl    $'0', %edx      # Turn into ASCII and store.
            decl    %ecx
            movb    %dl, (%ecx)

            cmpl    $0, %eax        # Continue until zero.
            jnz     olStore

            jmp     olPrint

olZero:     movl    $numLast, %ecx  # Load 0 into buffer.
            movb    $'0', (%ecx)

olPrint:    movl    $4, %eax        # SysWrite call.
            movl    $1, %ebx        #   File descriptor 1.
            movl    $numLast, %edx  #   Calculate length.
            incl    %edx
            subl    %ecx, %edx
            int     $0x80           #   And print.

            pop     %edx            # Clean up and return.
            pop     %ecx
            pop     %ebx
            pop     %eax
            ret

# ======================================================================
# Test harness.

.global _start
_start:     movl    $XYZZY, %eax    # Load up test value.
            call    outLong

            movl    $1, %eax        # SysExit, success.
            movl    $0, %ebx
            int     $0x80

The output of one particular run of the test harness follows:

Okay ('0')
Okay ('1')
Okay ('-1')
Okay ('9')
Okay ('10')
Okay ('-9')
Okay ('-10')
Okay ('99')
Okay ('100')
Okay ('2147483647')
Okay ('-2147483648')
Okay ('3700')
Okay ('-30889')
Okay ('19074')
Okay ('-19825')
Okay ('22601')
Okay ('-19364')
Okay ('9291')
Okay ('-24785')
Okay ('28133')
Okay ('-2892')
Okay ('20544')
Okay ('-10782')
Okay ('20878')
Okay ('-28479')
Okay ('13808')
Okay ('-9415')
Okay ('17693')
Okay ('-6797')
Okay ('16385')
Okay ('-10299')

In terms of what you need to add to your code, it's basically everything except the test harness at the end. Then, you call it with a simple:

mov $42, %eax     # Load EAX however you desire.
call outLong      # And print it.
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • My attempt at a canonical int->string answer is [Printing an integer as a string with AT&T syntax, with Linux system calls instead of printf](https://stackoverflow.com/a/45851398). And a NASM-syntax version in [How do I print an integer in Assembly Level Programming without printf from the c library?](https://stackoverflow.com/a/46301894) – Peter Cordes Oct 31 '18 at 03:10
  • Don't use `int 0x80` from 64-bit code! [What happens if you use the 32-bit int 0x80 Linux ABI in 64-bit code?](https://stackoverflow.com/q/46087730). Your code does actually work because you use a static storage location for everything you print, including the one-char-at-a-time print function instead of just pushing RBX last and using that byte. If anyone tries to build it into a PIE executable, it will fail to link (because of using 32-bit absolute addresses), rather than failing at runtime with `sys_write` returning `-EFAULT`. – Peter Cordes Oct 31 '18 at 07:18
  • Anyway, the OP appears to be writing 32-bit code, based on using a `(%ecx)` addressing mode and `int $0x80`. Use `gcc -m32` to assemble+link 32-bit executables if that's what you want, instead of carefully avoiding 64-bit addresses in 64-bit mode. (Or use the x32 ABI so stack addresses are in the low 32, but you're in 64-bit mode, but then you should still use `syscall` to make system calls instead of the 32-bit ABI.) – Peter Cordes Oct 31 '18 at 07:20
  • @Peter, I'm aware of the restrictions, and the conditions under which it will and won't work. It's just the OP seemed to be running 32-bit code and I didn't want to bring up a whole brand new VM just to test my changes :-) I'll insert warnings to that effect. – paxdiablo Oct 31 '18 at 07:21
  • What environment are you using where you can run a 64-bit executable with 32-bit `int 0x80` system calls (ruling out the Windows subsystem for Linux), but where you can't create and/or run pure 32-bit static executables with `gcc -m32 -static -nostdlib`? That doesn't require a 32-bit libc or anything, just the same toolchain you'd normally use on a 64-bit Linux system. All you need is kernel support for loading 32-bit ELF executables, which I think is controlled by the same `CONFIG_IA32_EMULATION` kernel config variable that enables support for the `int $0x80` ABI which you definitely have. – Peter Cordes Oct 31 '18 at 07:24
  • I'm not using `gcc`, I'm using `as` and `ld` directly. I'll try to find the equivalent options for testing but, for now, I'll just translate all the `rXX` registers into `eXX`. – paxdiablo Oct 31 '18 at 07:31
  • `as foo.S -o foo.o -g --32 && ld -o foo foo.o -m elf_i386`, from my answer on [Assembling 32-bit binaries on a 64-bit system (GNU toolchain)](/q/36861903). I normally just use gcc for GAS source, though, because I'd rather memorize the details of how `-nostdlib` vs. `-nostdinc` and `-static` work than remember `--32` and `-m elf_i386`. Plus I normally want to assemble+link with one command anyway, like I do with an "asm-link" wrapper script for NASM. – Peter Cordes Oct 31 '18 at 07:34
  • Thanks, Peter, I had the `as --32` I was trying to use the (apparently outdated) `ld --oformat elf32-i386`. It now appears to work in 32-bit mode as well. – paxdiablo Oct 31 '18 at 07:37
  • BTW, instead of making a `write` system call for every character (very slow, especially with spectre+meltdown mitigation), the easiest thing is to reserve like 16 bytes or something (longer than the longest possible ASCII decimal string from a 32-bit number), and store digits starting at the *end* of the buffer, decrementing a pointer. See the answers I linked in my first comment. It's much more elegent than a push/pop loop. Since you're passing it to `sys_write`, it doesn't matter where the first byte ends up, just that you have a pointer to it within the buffer. – Peter Cordes Oct 31 '18 at 07:52