【问题标题】:How to get the first command-line argument and put it into static buffer in memory?如何获取第一个命令行参数并将其放入内存中的静态缓冲区?
【发布时间】:2020-05-22 14:29:48
【问题描述】:

我想将第一个长度为 4 的命令行参数放入缓冲区。我可以通过以下方式获取它的每个字符:

.code64
.global _start

.bss

  .lcomm  mybuf , 4

.text
_start:

    mov   16(%rsp) ,  %rsi        #   argv[1]  
    movzx   (%rsi) ,  %ebx        #   first  char of argv[1]
    movzx  1(%rsi) ,  %ebx        #   second  char of argv[1]
    movzx  2(%rsi) ,  %ebx        #   third   char of argv[1]
    movzx  3(%rsi) ,  %ebx        #   fourth  char of argv[1]

  xor %rax , %rax
  inc %rax
  int $0x80

但是如何将长度为 4 的整个字符串放入我的缓冲区中呢?我的系统是带有 GAS 的 x64-Linux。

【问题讨论】:

  • 你试过类似mov (%rsi), %ebx; mov %ebx, mybuf(%rip)的东西吗?
  • 你想对那个字符串做什么?除非你想修改它,否则你可以在它所在的地方使用它。 16(%rsp) 是它的地址,它已经被空终止了。
  • 那是因为int 0x80 用于 32 位系统调用。如果您使用syscall 进行系统调用,则可以使用 64 位指针,它们可以指向堆栈或您想要的任何其他位置。
  • @Ston17 请注意,您真的不应该在 64 位代码中使用 int $0x80。相反,正如 Nate Eldredge 所说,使用syscall。请注意,系统调用号和寄存器在那里是不同的。
  • @Ston17 重新定位缓冲区并不重要。使用mybuf(%rip) 代替mybuf 来生成rip 相对寻址模式。 rip 不是正常意义上的基址寄存器。是的,您可以使用普通汇编中的syscall 指令。看来你有很多困惑。最好从汇编教程开始,而不是在 Stack Overflow 上随机提问。

标签: linux assembly x86 x86-64 gnu-assembler


【解决方案1】:

您不必将字符串本身的内容复制到数据缓冲区中。将16(%rsp) 的值保存在一个QWORD 大小的变量中,并在系统调用中随意使用它。用 C 语言来说,这就是

char lcomm[4];
strcpy(lcomm, argv[1]);
open(lcomm, ...);

char *plcomm;
plcomm = argv[1];
open(plcomm, ...);

第二个也一样。

此外,您的缓冲区的大小固定为 4 个字节。如果命令行参数比这个长,你的代码会溢出缓冲区,并可能崩溃。


也就是说,如果您认真学习汇编,您最终应该弄清楚如何编写类似strcpy 的循环。 :)


用一些汇编代码编辑。上次我检查时,文件名作为 RDI 进入系统调用,而不是 RSI:

mov   16(%rsp), %rdi # File name
mov   $0, %rsi        # Flags: O_RDONLY, but substitute your own
mov   $0, %rdx        # Mode: doesn't matter if the file exists
mov   $2, %rax        # Syscall number for open
syscall
# %rax is the file handle now

为了将来参考,x86_64 系统调用约定是:

  • 参数按顺序进入 %rdi、%rsi、%rdx、%rcx、%r8 和 %r9
  • 系统调用 # 进入 %rax
  • 然后执行syscall指令
  • 返回值在 %rax 中
  • %rcx 和 %r11 被破坏,其余寄存器被保留

系统调用的引用是here

【讨论】:

  • C 示例是为了说明逻辑。无论如何,请查看编辑。
  • 你知道如何调试你的程序集吗?
  • 我的错误,AT&T 语法不是我的原生语法。
  • 16(%rsp) 持有一个 qword 指针,而不是一个 dword。在_start 中,它是argv[1],它是char*。将堆栈指针截断为 32 位会导致段错误(或 -EFAULT 系统调用返回值)。还要注意open() 返回一个int fd。说 FD 在 EAX 中而不是 RAX 中会更准确。 (但您可以检查完整的 RAX 是否为 -4095 .. -1,所有 Linux 系统调用都返回错误代码,符号扩展为完整的寄存器宽度)。
  • 哦,我想你的意思是复制16(%rsp) 所指向的dword 指向,现在我重新阅读了这个问题。 OP 正在讨论在将指针加载到寄存器后复制字符串字节。
【解决方案2】:

解决了!

.code64
.global _start

.text

_start:

  mov   16(%rsp), %rdi  # File name from command-line first arg 
  mov   $0, %rsi        # Flags: O_RDONLY, but substitute your own
  mov   $0, %rdx        # Mode: doesn't matter if the file exists
  mov   $2, %rax        # Syscall number for open
  syscall
  mov %rax , %rbx

  mov $60, %rax
  syscall 

tnx 到塞瓦·阿列克谢耶夫

【讨论】:

  • 我们在这里表示感谢,接受和/或支持答案。
猜你喜欢
  • 2023-02-18
  • 1970-01-01
  • 2019-11-26
  • 2022-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-13
  • 1970-01-01
相关资源
最近更新 更多