How to rewrite a files content? Linux x86_64, assembly, GAS

╄→尐↘猪︶ㄣ 提交于 2021-02-11 12:29:31

问题


Hi ive got this exciting task, almost done actually.. but it fails in a funny aspect. The mission is to load a file with integers, sort them and write them to a file. Yay... Well my program is doing that, but it keeps the original content. ie:

lets say 45 32

Should get the ordered content 32 45

Well my program is keeping the original content and adds the new: 45 32 32 45.

So any sugestions on solving this? Though of deleting the original file and creating a new one in the same name. But thats kinda a failure, if the file has non-integers and my code has error reporting about that.

Ill give the important code here:

_OpenFile:
    movq $2, %rax           # open file
    movq $inputfile, %rdi   # filename
    movq $2, %rsi           # read and write
    movq $0644, %rdx        # setting proper permissions
    syscall
    ret

And:

_PrintNumber: #needs rdi as numberholder
    movq $1, %r9            # count the number of chars to print
    push $10                # store the chars on the stack, we always have '\n'
    movq %rdi, %rax         # things are easier with it in rax
    movq $10, %rcx
    decode_loop:
    movq $0, %rdx
    idivq %rcx              # do rdx:rax / rcx
    addq $48, %rdx          # convert the remainder to an ASCII digit
    pushq %rdx              # and save it on the stack
    addq $1, %r9            # while counting the number of chars
    cmpq $0, %rax
    jne decode_loop         # loop until rax == 0
    write_loop:
    movq $1, %rax           # write
    movq $3, %rdi           # to the file
    movq %rsp, %rsi         # which is stored here
    movq $1, %rdx           # a single character/byte
    syscall

    addq $8, %rsp           # pop the character
    addq $-1, %r9           # correct the char count

    jne write_loop          # loop until r9 reaches 0
    ret

Thanks to all who would like to comment this!


回答1:


It looks like you're either re-opening the file with O_APPEND, or you opened it read/write and didn't seek to the beginning before rewriting it. (So after reading the whole file, the position of the file descriptor is the end of the file, so newly-written data will go there.)

The lseek(2) system call is what you need to move the file position. lseek(fd, 0, SEEK_SET) rewinds to the beginning. (Args go in EDI, RSI, EDX, like normal for the x86-64 System V system-call convention, and the kernel interface matches the libc interface.)

Since the data you'll be writing out has the same length, you don't need to ftruncate(fd, len) the file before you start rewriting. You will overwrite all the bytes all the way to the end.


And BTW, you don't need to write each character separately; you can make a small buffer containing all the ASCII bytes for a number and make one write system call; much more efficient and actually takes less code: Printing an integer as a string with AT&T syntax, with Linux system calls instead of printf. My answer there also shows that you can #include <asm/unistd.h> and use code like
mov $__NR_write, %eax # SYS_write, from unistd_64.h
instead of using numeric literals for the system-call numbers, if you use a .S file so gcc will run it through the preprocessor.

Unfortunately, most headers like <unistd.h> (not asm/unistd.h) have C declarations as well, so you can't as easily get macros for constants like SEEK_SET or O_RDWR that would let you do mov $SEEK_SET, %edx or mov $O_WRONLY|O_CREAT|O_TRUNC, %esi.


Unlinking the file would have no effect on the contents of the already-open file; to get an effect like what you're picturing in the question, you could close/reopen the file. (In Unix, removing the directory entry for a file doesn't affect programs that already have it open. It will be freed from disk once the last directory entry and file-descriptor for it are gone, though.)

So you'd open it for reading, read all the data, and then (after checking for errors, when you're sure you have some valid data to write), open(infile, O_CREAT|O_TRUNC|O_WRONLY, 0666) and write out data. You didn't use O_APPEND, so the position of the new write-only FD will be at the front of the file. And the file-size will be truncated to 0. Exactly like echo foo > filename in the shell.

(It will still have the same inode number and be "the same file" with different contents unless you unlink(infile) before opening it to re-create a new file of that name. In that case O_CREAT is actually necessary. When reopening an existing file to write + truncate, O_CREAT isn't needed when the file already exists.)

The key here is to check for read errors before doing anything destructive, not just read it, destroy the original, and then continue on. So the file is still there on disk while you're sorting.



来源:https://stackoverflow.com/questions/53125140/how-to-rewrite-a-files-content-linux-x86-64-assembly-gas

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!