Assembly NASM打印时间-代码不';我什么也不输出

Assembly NASM打印时间-代码不';我什么也不输出,assembly,nasm,Assembly,Nasm,我刚刚开始使用ASM(NASM),需要以下代码片段的帮助。我没有收到任何错误/警告,只是没有输出任何内容。我所期望的是它得到时间(13),然后打印出来(4),然后退出(1)。还有,有人知道一些好的(最好是NASM特定的)ASM教程吗 section .bss time: resb 255 section .text global _start _start: mov eax, 13 int 0x80 mov eax, time mov edx

我刚刚开始使用ASM(NASM),需要以下代码片段的帮助。我没有收到任何错误/警告,只是没有输出任何内容。我所期望的是它得到时间(13),然后打印出来(4),然后退出(1)。还有,有人知道一些好的(最好是NASM特定的)ASM教程吗

section .bss
  time:   resb   255

section .text
  global _start

_start:
  mov   eax, 13
  int   0x80
  mov   eax, time

  mov   edx, 255
  mov   ecx, time
  mov   ebx, 1
  mov   eax, 4
  int   0x80

  mov   eax, 1
  int   0x80

这是翻译成C的示例。您将指向时间的指针复制到eax,而不是eax到缓冲区。但这仍然不起作用,因为您需要用于写入的字符数组,而不是将打印垃圾的原始整数

#include <stdlib.h>

char b[255];

int
main()
{
        /* You wanted to do this which doesn't work
         * because write wont take int* but char arrays
         * *(int*)b=time(NULL);
         */

        /* Instead you did */
        time(NULL);
        b;
        write(1, b, 255);
        exit(1);
}
#包括
字符b[255];
int
main()
{
/*你想这么做,但没用
*因为write不接受int*而接受char数组
**(int*)b=时间(空);
*/
/*相反,你做到了*/
时间(空);
B
写入(1,b,255);
出口(1);
}

这是您翻译为C的示例。您正在将指向时间的指针复制到eax,而不是将eax复制到缓冲区。但这仍然不起作用,因为您需要用于写入的字符数组,而不是将打印垃圾的原始整数

#include <stdlib.h>

char b[255];

int
main()
{
        /* You wanted to do this which doesn't work
         * because write wont take int* but char arrays
         * *(int*)b=time(NULL);
         */

        /* Instead you did */
        time(NULL);
        b;
        write(1, b, 255);
        exit(1);
}
#包括
字符b[255];
int
main()
{
/*你想这么做,但没用
*因为write不接受int*而接受char数组
**(int*)b=时间(空);
*/
/*相反,你做到了*/
时间(空);
B
写入(1,b,255);
出口(1);
}

这里的第一个问题是您需要理解sys\u time sys调用。这里有一个方便的图表,告诉您各种sys调用需要什么作为寄存器中的输入

系统时间是系统调用13,所以

mov eax,13
很好

然而,sys_time还需要在ebx中传递一个内存地址,它在ebx中写入实际时间

一个快速的方法是在堆栈上分配一些空间(我们可以在堆栈上推送任何东西,sys_time值将覆盖它,为什么不将eax的值粘贴到它上)

然后将堆栈指针馈送到ebx

mov ebx, esp
现在进行系统调用

int 80h
现在,我们可以从堆栈中弹出时间(例如,eax)

现在eax包含当前unix时间(即自1970年1月1日起的秒数)

为了避免直接将数字打印到unix控制台的麻烦,我将作弊并提供一个完整的示例,该示例在nasm中编译,并通过gcc与c库链接,并使用printf

[SECTION .data]
PrintNum    db "%d",10,0 ;this is a c string so is null terminated
[SECTION .text]
extern printf       
global main

main:
        push ebp
    mov ebp,esp
    push ebx
    push esi
    push edi        ; stuff before this for glibc compatibility

    mov eax, 13
    push eax
    mov ebx, esp
    int 0x80
    pop eax

    push eax        ; push eax onto stack then the format string, then call printf to write eax to console, unwind stack pointer
    push PrintNum
    call printf 
    add esp,8   


    pop edi         ; stuff after this for glibc compatibility
    pop esi
    pop ebx
    mov esp,ebp
    pop ebp
    ret
编译

nasm -f elf sys_time.asm
gcc sys-time.o -o sys-time
不过,如果您使用的是64位linux,您可能必须这样做(并拥有相关的多库gcc和glibc)。无法将此程序编译为本机64位可执行文件,因为它使用push和pop,并且无法将32位寄存器推送到64位堆栈上

nasm -f elf32 sys_time.asm
gcc -m32 sys-time.o -o sys-time
那你应该去

$ ./systime
1310190574
我已经在32位和64位linux上进行了测试,并成功地编译了上述代码。如果你有任何问题,请告诉我


为了回答您关于nasm教程的问题,我最近学习了杰夫·邓特曼的“汇编语言分步学习,第三版”。有关详细信息和示例章节,请参见。

这里的第一个问题是您需要了解sys\u time sys调用。这里有一个方便的图表,告诉您各种sys调用需要什么作为寄存器中的输入

系统时间是系统调用13,所以

mov eax,13
很好

然而,sys_time还需要在ebx中传递一个内存地址,它在ebx中写入实际时间

一个快速的方法是在堆栈上分配一些空间(我们可以在堆栈上推送任何东西,sys_time值将覆盖它,为什么不将eax的值粘贴到它上)

然后将堆栈指针馈送到ebx

mov ebx, esp
现在进行系统调用

int 80h
现在,我们可以从堆栈中弹出时间(例如,eax)

现在eax包含当前unix时间(即自1970年1月1日起的秒数)

为了避免直接将数字打印到unix控制台的麻烦,我将作弊并提供一个完整的示例,该示例在nasm中编译,并通过gcc与c库链接,并使用printf

[SECTION .data]
PrintNum    db "%d",10,0 ;this is a c string so is null terminated
[SECTION .text]
extern printf       
global main

main:
        push ebp
    mov ebp,esp
    push ebx
    push esi
    push edi        ; stuff before this for glibc compatibility

    mov eax, 13
    push eax
    mov ebx, esp
    int 0x80
    pop eax

    push eax        ; push eax onto stack then the format string, then call printf to write eax to console, unwind stack pointer
    push PrintNum
    call printf 
    add esp,8   


    pop edi         ; stuff after this for glibc compatibility
    pop esi
    pop ebx
    mov esp,ebp
    pop ebp
    ret
编译

nasm -f elf sys_time.asm
gcc sys-time.o -o sys-time
不过,如果您使用的是64位linux,您可能必须这样做(并拥有相关的多库gcc和glibc)。无法将此程序编译为本机64位可执行文件,因为它使用push和pop,并且无法将32位寄存器推送到64位堆栈上

nasm -f elf32 sys_time.asm
gcc -m32 sys-time.o -o sys-time
那你应该去

$ ./systime
1310190574
我已经在32位和64位linux上进行了测试,并成功地编译了上述代码。如果你有任何问题,请告诉我


为了回答您关于nasm教程的问题,我最近学习了杰夫·邓特曼的“汇编语言分步学习,第三版”。有关详细信息和示例章节,请参阅。

不要自责。所有的装配都很糟糕可能值得一提的是您使用的是哪个平台。我使用的是64位Linux,使用的是NASM。@kyl,我想您是在组装32位二进制文件,对吗?因为在64位Linux中,您必须使用64位asm,它看起来与您发布的完全不同。而且,即使它是预期的32位二进制文件,我认为您正在尝试写入(2)一个整数或时间,这取决于您使用的系统调用。不要自责。所有的装配都很糟糕可能值得一提的是您使用的是哪个平台。我使用的是64位Linux,使用的是NASM。@kyl,我想您是在组装32位二进制文件,对吗?因为在64位Linux中,您必须使用64位asm,它看起来与您发布的完全不同。而且,即使它按预期的32位二进制格式工作,我认为您正在尝试写入(2)一个整数或时间,具体取决于您使用的系统调用。sys write在ECX中使用指针,而不是EBX。你想要推…<代码>移动ecx,esp
int 0x80
将推送字节写入标准输出。sys\u write在ECX而不是EBX中使用指针。你想要推…<代码>移动ecx,esp
int 0x80
将推送字节写入标准输出。