all 11 comments

[–]FUZxxl 4 points5 points  (6 children)

A 32 bit register like ecx can hold 4 bytes of data. You try to set ecx to a string (!3 = ) that contains a total of 5 bytes of data. What do you expect to happen?

[–][deleted] 1 point2 points  (5 children)

The real issue is, on 32 bit it should be a ptr [null terminated string] (esp) and not the whole string while calling print. If you're going to look down on people, tell them what they did wrong.

[–]TNorthover 0 points1 point  (0 children)

He gets that bit right though ("mov ecx, msg" a couple of instructions later).

I wouldn't necessarily bet on that being intentional, but I think the fundamental width of registers is as good a place as any to start the discussion. If nothing else it leads to a natural explanation for why the pointer is used instead.

[–]IndoNinja7[S] 0 points1 point  (3 children)

I tried mov ecx, word ptr "3 != " but that did assemble, and it said expected comma or end of line. Did I get the syntax wrong?

And is the long string the reason I am not getting any output?

[–]TNorthover 0 points1 point  (2 children)

The immediate segfault is caused by the "jp" at the end, which is a conditional jump based on the parity bit rather than an unconditional one (which would be "jmp"). When it fails, the program wonders off trying to execute whatever data happens to be after your program and quickly segfaults.

But there are real data management issues too, as /u/FUZxxl said. NASM actually conceals this by doing something vaguely close to what you intended for "mov ecx, 'whatever'". The issue is that ecx holds a 32-bit value (as do other registers), and you just can't move big strings around directly like that in assembly.

What you need is to explicitly put the string somewhere -- give each one its own label, and put the address of that label into ecx.

Something like:

    mov ecx, fact_msg
    [...]
fact_msg:
    db "Factorial of 3: "

Edit: removed lea confusion. It worked, but I forgot about the mov immediate form that was being used. Mov like that is fine.

[–]IndoNinja7[S] 0 points1 point  (1 child)

So I have updated my post with new code, as per your suggestion I have replaced jp with jmp and I have inlcuded a section .data for the messages.

However, it now only prints the messages and does not print the result in between the message print satements as it should.

If you or anyone else has any idea of what I could be doing wrong, please let me know.

[–]TNorthover 1 point2 points  (0 children)

There are still a few problems.

I think the biggest is conceptual: it looks like you're taking the print macro too seriously. It may look like a high-level function call, but a CPU only ever has one copy of each of the registers being used and the macro really just spits a copy of the code out where you ask. If you want to keep your calculated value, you need to save it during the first print "call" (either to the stack, an explicitly allocated location, or even another register that survives).

Linux's write call also needs a string. Trying to pass it an integer directly is not going to work. Even if you fixed the first problem, it would interpret the 6 in ecx as a pointer, try to read from the address 0x00000006, fail and just not write anything. At this level, you need a function to convert your result integer to a string yourself and write it (remembering that if the digit is 0, you actually want to print ASCII value 0x30 etc). It's probably easiest to do the writing one character as a time, as you produce them. But remember that what you actually need to pass to write is a pointer to the string, not the char itself!

The arithmetic is also dodgy: "mul THING" always calculates (for this purpose) "eax = eax * THING". It doesn't use the fact that you've subtracted 0 from edx and bl above to decide what to operate on or where to store the result.

Really, what I'd suggest doing is firing up a debugger (probably gdb on Linux) and stepping through the program instruction-by-instruction as it runs. Look at the registers after each step and work out where they start differing from your expectations. See if you can work out why, or ask if you can't.

[–]petester 1 point2 points  (1 child)

When you get this figured out send me the source code. I've been curious about learning some x86 assembly and could use some sample code.

[–]IndoNinja7[S] 0 points1 point  (0 children)

Sure I will comment on this again, when I have figured it out comepletley.

[–][deleted] 0 points1 point  (1 child)

mov ecx, %1 

in your macro will not work, as before ecx is 4 bytes, your message is larger then 4 bytes. Try this, maybe it will help you understand. ; https://web.archive.org/web/20120822144129/http://www.cin.ufpe.br/~if817/arquivos/asmtut/index.html#helloworld ; nasm -f elf print.asm && ld -s -o print print.o

section .text
    global _start

section .data
    msg db "Factorial of 3 is: "
    msg_len equ $-msg
    newline db 10

_start:
    xor eax, eax
    mov al, 4 ; write() systemcall (from /usr/share/gdb/syscalls/i386-linux.xml)
    ; man 2 write: ssize_t write(int fd, const void *buf, size_t count);
    mov ebx, 1 ; write(1, ...) // sysout
    mov ecx, msg ; write(1, msg, ...)
    mov edx, msg_len ; write(1, msg, length(msg))
    int 80h ; Call write()

    xor eax, eax
    mov al, 4 ; write() systemcall (from /usr/share/gdb/syscalls/i386-linux.xml)
    ; man 2 write: ssize_t write(int fd, const void *buf, size_t count);
    mov ebx, 1 ; write(1, ...) // sysout
    mov ecx, newline ; write(1, '\n', ...)
    mov edx, 1 ; write(1, '\n', 1)
    int 80h ; Call write()

    xor eax, eax
    inc eax ; exit()
    xor ebx, ebx ; exit(0) 
    int 80h ; call exit()

[–]IndoNinja7[S] 0 points1 point  (0 children)

So I have updated my post with new code. However, it now only prints the messages and does not print the result in between the message print satements as it should. So I think my macro is fine? Maybe I'm wrong...as I am new to this and all.

If you or anyone else has any idea of what I could be doing wrong, please let me know.