【问题标题】:Print ARGC in NASM without printf在没有 printf 的 NASM 中打印 ARGC
【发布时间】:2016-01-25 23:14:58
【问题描述】:

那里有好的 NASM/Intel 汇编程序员吗?如果是这样,我有一个问题要问你!

我可以在网上找到的每个教程都显示了“printf”的用法,用于将 ARGC 的实际值打印到屏幕上(fd:/dev/stdout)。是不是可以简单地用 sys_write() 打印它,例如:

SEGMENT .data ; nothing here

SEGMENT .text ; sauce
        global _start
        _start:
                pop ECX ; get ARGC value
                mov EAX, 4 ; sys_write()
                        mov EBX, 1 ; /dev/stdout
                        mov EDX, 1 ; a single byte
                int 0x80
                mov EAX, 1 ; sys_exit()
                        mov EBX, 0 ; return 0
                int 0x80
SEGMENT .bss ; nothing here

当我运行它时,我根本没有得到任何输出。我尝试将 ESP 复制到 EBP 并尝试使用 byte[EBP+4],(我被告知括号取消引用内存地址)。

我可以确认,与常数相比,该值有效。例如, 此代码有效:

pop ebp ; put the first argument on the stack
mov ebp, esp ; make a copy 
cmp byte[ebp+4],0x5 ; does it equal 5?
je _good ; goto _good, &good, good()
jne _bad ; goto _bad, &bad, bad()

当我们“弹出”堆栈时,从技术上讲,我们应该得到完整数量的参数,不是吗?哦,顺便说一句,我编译:

nasm -f elf test.asm -o test.o
ld -o test test.o

不确定这是否相关。如果我需要提供更多信息或格式化我的代码以提高可读性,请告诉我。

【问题讨论】:

  • sys_write 接受一个指向字符串的指针(以及数组中的字符数)。您需要将您的数字 argc 转换为字符串,然后将指向该字符串的指针传递给 sys_write 系统调用。
  • 用 C 语言编写一些东西并查看编译器输出通常很有用。特别是。在您学习时,它会发现这样的错误(write(2) 需要值与指针)。此外,使用pop 获取参数很奇怪。它在_start 中工作,但在任何其他上下文中,堆栈底部将保存您的返回地址。另外,pop ebp / mov ebp, esp 很奇怪。如果您要在下一条指令中覆盖 ebp,为什么不直接使用 add esp, 4?如果您还没有看到,请查看agner.org/optimizestackoverflow.com/tags/x86/info 上的其他链接
  • @kp101st:你不应该在标题中加上“SOLVED”。如果有一个答案可以解决您的问题,请将其标记为已接受(如果您愿意,也可以投票)。
  • @Michael 谢谢!我是新手! :S

标签: linux assembly x86 nasm


【解决方案1】:

至少有 2 个问题。

  1. 您需要将指针传递给要打印的内容。
  2. 您可能想要转换为文本。

这样的事情应该可以工作:

SEGMENT .text ; sauce
        global _start
        _start:
                mov ecx, esp        ; pointer to ARGC on stack
                add byte [esp], '0' ; convert to text assuming single digit
                mov EAX, 4 ; sys_write()
                mov EBX, 1 ; /dev/stdout
                mov EDX, 1 ; a single byte
                int 0x80
                mov EAX, 1 ; sys_exit()
                mov EBX, 0 ; return 0
                int 0x80

【讨论】:

  • 不应该是pointer to ARGV on stackpointer to ARGC on stack
  • @Jester 谢谢!那肯定是错的。并且获得 ARGV[0] 的新行在我的系统中完美运行!谢谢!!
  • @Michael 谢谢!很好,我会更新我原来帖子中的评论:)
【解决方案2】:

每个人的 cmets 都非常有帮助!很荣幸大家的参与和帮助!我用过@Jester的代码,

SEGMENT .text ; sauce
        global _start
        _start:
                mov ecx, esp        ; pointer to ARGC on stack
                add byte [esp], '0' ; convert to text assuming single digit
                mov EAX, 4 ; sys_write()
                mov EBX, 1 ; /dev/stdout
                mov EDX, 1 ; a single byte
                int 0x80
                mov EAX, 1 ; sys_exit()
                mov EBX, 0 ; return 0
                int 0x80

在编译、链接和加载时完美运行。 sys_write() 函数需要一个指针,例如在常见的“Hello World”示例中,符号“msg”是一个指针,如下面的代码所示。

SECTION .data ; initialized data
    msg: db "Hello World!",0xa
SECTION .text ; workflow
    global _start
    _start:
        mov EAX, 4
        mov EBX, 1
        mov ECX, msg ; a pointer!

首先,我们将 堆栈指针 移动到计数器寄存器 ECX 中,并使用代码

mov ecx, esp ; ecx now contains a pointer!

然后通过将“0”字符添加到 ESP(即 ARGC)指向的值,通过 取消引用 将其转换为字符串方括号,就像[ESP]这样,

add byte[esp], '0' ; update the value stored at "esp"

再次感谢大家的大力帮助!

【讨论】:

  • 既然 Jester 的回答解决了你的问题,你应该接受他的回答。请看这个关于how/why you should accept answers
  • @MichaelPetch 我刚刚读到了,从现在开始我会读到的。感谢您的帮助!我真的不喜欢遇到让我难以发帖、互动和提问等问题的问题,因为我是一个忙碌的人。但是,我其实已经迫不及待想要再拥有一个了,只是为了向大家学习!我喜欢这个网站! :)
猜你喜欢
  • 2013-12-14
  • 1970-01-01
  • 2020-06-07
  • 2019-07-06
  • 1970-01-01
  • 1970-01-01
  • 2015-08-07
  • 2015-09-17
  • 2015-06-09
相关资源
最近更新 更多