0

I am learning to use only system calls to open, read, and write in assembly language. I'm trying to open a simple text file called "file1.txt", read the file and write the contents to another file called fileOUT.txt. With the help of some of you I've been able to get the code to run without any obvious errors, but it won't actually write to the fileOUT file. I'm running x86 on linux. I did run a strace on the program. It appears it doesn't like the address of the write file fileOUT though I'm not sure why. Here's a link to the strace and the code I'm trying to run.

https://i.stack.imgur.com/bYplM.png --strace, not allowed to paste yet

section .data
        readFile:    db      "file1.txt", 0
        len:         db      15
        writeFile:   db      "fileOUT.txt", 0
section .bss
        fd_outfile:  resb 4
        fd_infile:   resb 4
        buffer:      resb 15

section .text
        global main

main:
        ;start stack
        push ebp
        mov  ebp, esp
        
        ; open file1.txt
        mov eax,    5
        mov ebx,    readFile
        mov ecx,    0
        mov edx,    0777
        int 80h

        ;move file descriptor to variable
        mov  [fd_infile], eax       
    
        ;read from file
        mov eax, 3
        mov ebx, [fd_infile]
        mov ecx, buffer
        mov edx, len
        int 80h
        
        ;close file1
        mov eax,6
        mov ebx,[fd_infile]
        int 80h

        ; open fileOUT.txt
        mov eax,    5
        mov ebx,    writeFile
        mov ecx,    1
        mov edx,    0777
        int 80h

        ; moves file descriptor to variable
        mov [fd_outfile], eax
        
        ; write to fileOUT
        mov eax,    4               ;system call number (sys_write)
        mov ebx,    [fd_outfile]    ;file descriptor 
        mov ecx,    buffer          ;message to write
        mov edx,    len             ;number of bytes     
        int 80h
        
        ;close fileOUT
        mov eax,6
        mov ebx,[fd_outfile]
        int 80h

        ; exit program        
        mov esp, ebp
        pop ebp
        ret

Editor's note: The error is in mov edx, len ;number of bytes. This requires the use of square brackets and needs to extend the byte to dword: movzx edx, byte [len].

BIG THANKS to Everyone!!!. My program now works and I also learned a lot from all your input.

Adam Braun
  • 11
  • 2
  • "always get an error at the INT 0x80 line." That's pretty vague; would you please say what the error is? Exactly what message do you see in your debugger? – Nate Eldredge Nov 06 '22 at 18:13
  • 2
    Just to check, you are properly building this as a 32-bit executable, yes? What does `file prog.bin` print out, where `prog.bin` is the name of your executable? – Nate Eldredge Nov 06 '22 at 18:14
  • 1
    `add esp, 4` to "restore the stack pointer" doesn't make sense because you never *did* anything to the stack pointer. So this will result in crashing when you get to the `ret`, if you actually get that far. Perhaps there used to be a `push` further up that got removed? – Nate Eldredge Nov 06 '22 at 18:16
  • `mov [fd_infile], eax` is a 32-bit move, which is proper because a file descriptor is a 32-bit integer (4 bytes). Unfortunately `fd_infile resb 1` reserves only 1 byte, so you overwrite 3 other bytes that you shouldn't. Make it `fd_infile resb 4` and the same for `fd_outfile`. – Nate Eldredge Nov 06 '22 at 18:18
  • `readFile db "file1.txt"` doesn't null-terminate the string, which system calls need. So make it `readFile db "file1.txt", 0` and the same for your other strings. I suspect this is the bug that causes the open system call to fail, since it will treat the following bytes in memory as part of the file name, and naturally no file with that weird name will be found. – Nate Eldredge Nov 06 '22 at 18:20
  • `xor ecx,ecx`: If you write your code with a `main` function, so that it is called by the C startup code, and return from it with `ret` instead of invoking the `_exit` system call, then it needs to return a value following the usual C calling conventions: in `eax`. So make it `xor eax, eax` instead. – Nate Eldredge Nov 06 '22 at 18:24
  • Oh, and if you are writing a `main` function to be called like C, then you also need to respect C calling conventions on register preservation. In the x86-32 ABI, the registers `ebx, ebp, esi, edi` are call-preserved, so in particular you must save `ebx` at the start of your code and restore it before returning. – Nate Eldredge Nov 06 '22 at 18:27
  • You get an error at `int 0x80`? Is your Linux system actually WSL1 under Windows? Or a real Linux system like Gentoo with a kernel built without CONFIG_IA32_EMULATION? If so, then it also won't even run at all if you link with `gcc -m32` to actually make a 32-bit executable, like you should for 32-bit code using 32-bit pointers like ESP, and the 32-bit `int 0x80` ABI. ([What happens if you use the 32-bit int 0x80 Linux ABI in 64-bit code?](https://stackoverflow.com/q/46087730)) – Peter Cordes Nov 06 '22 at 22:06
  • `int 0x80` should never crash except on a kernel without IA32_EMULATION. It will just return an error code, like `-EFAULT` if the low 32 bits of a register aren't a valid pointer. – Peter Cordes Nov 06 '22 at 22:17
  • As Sep says, either `movzx` to load that byte from `.data` into EDX, or make it an `equ` constant so `mov edx, len` will give you the small number instead of an address. See [How does $ work in NASM, exactly?](https://stackoverflow.com/q/47494744) and [Basic use of immediates vs. square brackets in YASM/NASM x86 assembly](https://stackoverflow.com/q/10362511) for details on how that works. – Peter Cordes Nov 08 '22 at 00:02

0 Answers0