【问题标题】:How to rewrite a files content? Linux x86_64, assembly, GAS如何重写文件内容? Linux x86_64,程序集,GAS
【发布时间】:2019-04-07 02:03:42
【问题描述】:

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

让我们说 45 32

应该得到有序的内容 32 45

好吧,我的程序保留了原始内容并添加了新内容: 45 32 32 45。

那么有什么解决这个问题的建议吗?尽管删除了原始文件并以相同的名称创建了一个新文件。但这有点失败,如果文件包含非整数并且我的代码有错误报告。

这里给出重要的代码:

_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

感谢所有愿意对此发表评论的人!

【问题讨论】:

  • 您好,请编辑问题以包含您的源代码。目前我们根本没有什么可做的。谢谢。
  • 当然 :P 虽然它可能更笼统。
  • 离题系统编程提示:您应该使用$0666 与O_CREAT 一起打开并让您的umask 设置将其屏蔽为06640644,根据用户的选择。您通常只对私人文件使用更有限的权限(例如写入您的电子邮件邮箱的程序,或加密保存的密码),它可能会使用0600 权限创建文件。

标签: linux x86-64 gnu-assembler


【解决方案1】:

看起来您要么使用O_APPEND 重新打开文件,要么以读/写方式打开它,并且在重写之前没有寻找开头。 (所以读取整个文件后,文件描述符的位置是文件的末尾,所以新写入的数据会到那里。)

lseek(2) system call 是移动文件位置所需要的。 lseek(fd, 0, SEEK_SET) 倒回到开头。 (Args 进入 EDI、RSI、EDX,就像 x86-64 System V 系统调用约定一样,内核接口与 libc 接口匹配。)

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


顺便说一句,您不需要分别write 每个字符;您可以创建一个包含数字的所有 ASCII 字节的小缓冲区,然后进行一个 write 系统调用;效率更高,实际上需要更少的代码:Printing an integer as a string with AT&T syntax, with Linux system calls instead of printf。我的回答还表明您可以#include <asm/unistd.h> 并使用类似
mov $__NR_write, %eax # SYS_write, from unistd_64.h
的代码 如果您使用 .S 文件而不是使用数字文字作为系统调用号,那么 gcc 将通过预处理器运行它。

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


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

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

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

这里的关键是在做任何破坏性的事情之前检查读取错误,而不是仅仅阅读它,破坏原件,然后继续。因此,在您进行排序时,该文件仍然存在于磁盘上。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-04-20
    • 1970-01-01
    • 2021-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-19
    • 1970-01-01
    相关资源
    最近更新 更多