如何重写文件内容?Linux x86_64,汇编,GAS [英] How to rewrite a files content? Linux x86_64, assembly, GAS

查看:18
本文介绍了如何重写文件内容?Linux x86_64,汇编,GAS的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我完成了这项激动人心的任务,实际上几乎完成了......但它在一个有趣的方面失败了.任务是加载一个带有整数的文件,对它们进行排序并将它们写入文件.是的...嗯,我的程序正在这样做,但它保留了原始内容.即:

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:

让我们说4532

应该得到有序的内容32 45

Should get the ordered content 32 45

好吧,我的程序保留了原始内容并添加了新内容:45 32 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

还有:

_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!

推荐答案

看起来您要么使用 O_APPEND 重新打开文件,要么以读/写方式打开它但没有在重写它之前寻求开始.(所以读完整个文件后,文件描述符的位置就是文件的末尾,所以新写入的数据会到那里去.)

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.)

lseek(2)系统调用是你移动文件位置所需要的.lseek(fd, 0, SEEK_SET) 倒回到开头.(参数在 EDI、RSI、EDX 中,就像 x86-64 System V 系统调用约定的正常情况一样,并且内核接口与 libc 接口匹配.)

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.)

由于您将要写出的数据具有相同的长度,因此您无需在开始重写之前ftruncate(fd, len) 文件.您将一直覆盖所有字节.

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.

顺便说一句,你不需要分别write每个字符;您可以制作一个包含数字的所有 ASCII 字节的小缓冲区,并进行一次 write 系统调用;效率更高,实际上需要更少的代码:使用 AT&T 语法将整数打印为字符串,使用 Linux 系统调用而不是 printf.我在那里的回答还表明您可以 #include <asm/unistd.h> 并使用类似
mov $__NR_write, %eax # SYS_write, from unistd_64.h
如果您使用 .S 文件,而不是使用数字文字作为系统调用号,那么 gcc 将通过预处理器运行它.

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.

不幸的是,像 <unistd.h>(不是 asm/unistd.h)这样的大多数头文件也有 C 声明,所以你不能轻易得到SEEK_SETO_RDWR 等常量的宏可以让你做 mov $SEEK_SET, %edxmov $O_WRONLY|O_CREAT|O_TRUNC, %esi.

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.

取消链接文件不会影响已打开文件的内容;要获得您在问题中所描绘的效果,您可以关闭/重新打开文件.(在 Unix 中,删除文件的目录条目不会影响已经打开它的程序.它会但是,一旦最后一个目录条目和它的文件描述符消失,就可以从磁盘中释放出来.)

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.)

所以你会打开它进行读取,读取所有数据,然后(在检查错误之后,当你确定你有一些有效的数据要写入时),open(infile, O_CREAT|O_TRUNC|O_WRONLY, 0666) 并写出数据.您没有使用 O_APPEND,因此新的只写 FD 的位置将位于文件的前面.并且文件大小将被截断为 0.就像 echo foo >文件名在shell中.

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.

(除非您在打开它以重新创建该名称的新文件之前unlink(infile),否则它仍然具有相同的inode编号并且是具有不同内容的同一个文件".在这种情况 O_CREAT 实际上是必要的.重新打开现有文件以写入 + truncate 时,如果文件已经存在,则不需要 O_CREAT.)

(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.

这篇关于如何重写文件内容?Linux x86_64,汇编,GAS的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆