2

因此,作为我的计算机体系结构课程的一部分,我需要熟悉组装,或者至少足够舒适,我正在尝试向用户读取输入然后重新打印它(暂时),这就是我尝试的方式用伪代码进行说明:

  1. 声明 msg 变量(这将打印在屏幕上)
  2. 用足够长的值声明长度变量(由 sys_write 函数使用)
  3. 出栈一次,获取程序名
  4. 再次弹出堆栈以获取第一个参数
  5. 将堆栈的当前值移动到 msg 变量中
  6. 将 msg 移至 ECX(sys_write 参数)
  7. 将长度移动到 EDX(sys_write 参数)
  8. 使用标准输出调用 sys_write
  9. 内核调用
  10. 调用 sys_exit 并离开

到目前为止,这是我的代码

section .data
  msg:    db 'placeholder text',0xa;
  length: dw 0x123;

section .text
  global _start 

    _start: 
      pop rbx;
      pop rbx;
      ; this is not working when I leave it in I get this error:
      ; invalid combination of opcode and operands                                                                                            
      ;mov msg, rbx;
      mov ecx, msg;
      mov edx, length;

      mov eax, 4;
      mov ebx, 1;
      int 0x80;
      mov ebx, 0;
      mov eax, 1;
      int 0x80;

当我忽略它(不将参数移动到 msg 中)时,我得到了这个输出

placeholder text
#.shstrtab.text.data
                     �@�$�`��

我们真的刚刚开始使用 NASM,所以任何帮助都将不胜感激,我一直在看这个http://www.cin.ufpe.br/~if817/arquivos/asmtut/index.html#stackhttp:// syscalls.kernelgrok.com/调整示例以根据我的理解调整注册表名称以匹配http://www.nasm.us/doc/nasmdo11.html

我正在运行 Ubuntu 12.04,64 位编译(甚至不确定这是否是正确的词)ELF64 下的 NASM,很抱歉提出这样一个愚蠢的问题,但我一直无法为使用 64 位的 NASM 找到足够简单的教程.

4

3 回答 3

4

调用程序时,堆栈应如下所示:

+----------------+
| ...            | <--- rsp + 24
+----------------+
| argument 2     | <--- rsp + 16
+----------------+
| argument 1     | <--- rsp + 8
+----------------+
| argument count | <--- rsp
+----------------+

第一个参数是程序的名称,第二个是用户输入(如果用户键入任何内容作为参数)。所以参数的数量至少为 1。

64 模式系统调用的参数存储在以下寄存器中:

  • rax(系统调用号)
  • rdi(第一个参数)
  • rsi(第二个参数)
  • rdx(第三个参数)
  • rcx(第四个参数)
  • r8(第五个参数)
  • r9(第 6 个参数)

系统调用是用 调用的syscall。所有系统调用的编号都可以在这里 找到(是的,它们与 32 位模式下的编号不同)。

这是应该做你的事情的程序:

section .data
    msg:    db 'Requesting 1 argument!', 10  ; message + newline

section .text
    global  _start

_start:
    cmp     qword [rsp], 2    ; check if argument count is 2
    jne     fail              ; if not jump to the fail lable

    mov     rax, 1            ; sys_write
    mov     rdi, 1            ; stdout
    mov     rsi, [rsp+16]     ; get the address of the argument 
    mov     rdx, 1            ; one character (length 1)

loop:
    cmp     byte [rsi], 0     ; check if current character is 0
    je      exit              ; if 0 then jump to the exit lable
    syscall
    inc     rsi               ; jump to the next character
    jmp     loop              ; repeat

fail:
    mov     rax, 1            ; sys_write
    mov     rdi, 1            ; stdout
    lea     rsi, [rel msg]    ; move the address of the lable msg in rsi
    mov     rdx, 23           ; length = 23
    syscall

exit:
    mov     rax, 60           ; sys_exit
    mov     rdi, 0            ; with code 0
    syscall

由于代码在很多方面都不是完美的,因此您可能需要对其进行修改。

于 2012-11-30T15:12:14.560 回答
2

您已经完全按照说明进行了操作——这是预期的输出。

您写入消息的堆栈变量只是一些二进制值——确切地说,它是指向包含命令行参数的字符串数组的指针。为了理解这一点,您要么必须打印这些字符串,要么将指针转换为 ascii 字符串,例如。“0x12313132”。

于 2012-11-30T07:22:38.487 回答
2

我的操作系统是 Ubuntu 64 位。编译代码产生了错误:

nasm print3.asm 

print3.asm:12: error: instruction not supported in 16-bit mode
print3.asm:13: error: instruction not supported in 16-bit mode

正是“pop rbx”所在的位置。

在 asm 文件的顶部添加“BITS 64”解决了这个问题:

BITS 64

section .data
  msg:    db 'placeholder text',0xa;
  length: dw 0x123;

...
于 2015-02-12T02:30:17.310 回答