我需要制作一个程序来输出扩展名为 .dna 的文本文件,我不知道我是否真的可以做到这一点,以及该文本文件是否与我之后需要比较的内容兼容。无论如何,我不太确定该怎么做。我试图寻找一些 NASM 的例子,但没有找到太多。我知道我需要做什么,但我只是不知道要调用什么来生成文件。
之后我需要在其中写入一些内容,我不太确定如何继续下去。有人能给我举一些例子或其他什么吗?我只需要看看编写自己的东西需要什么。
最佳答案
这是一个使用系统调用的示例。基本上,您只需打开文件,向其中写入一些数据,然后关闭并退出:
; nasm -f elf file.asm
; ld -m elf_i386 file.o
BITS 32
section .data
; don't forget the 0 terminator if it akes a C string!
filename: db 'test.txt', 0
; an error message to be printed with write(). The function doesn't
; use a C string so no need for a 0 here, but we do need length.
error_message: db 'Something went wrong.', 10 ; 10 == \n
; this next line means current location minus the error_message location
; which works out the message length.
; many of the system calls use pointer+length pairs instead of
; 0 terminated strings.
error_message_length: equ $ - error_message
; a message we'll write to our file, same as the error message
hello: db 'Hello, file!', 10 ; the 10 is a newline at the end
hello_length: equ $ - hello
fd: dd 0 ; this is like a global int variable in C
; global variables are generally a bad idea and there's other
; ways to do it, but for simplicity I'm using one here as the
; other ways are a bit more work in asm
section .text
global _start
_start:
; first, open or create the file. in C it would be:
; // $ man 2 creat
; int fd = creat("file.txt", 0644); // the second argument is permission
; we get the syscall numbers from /usr/include/asm/unistd_32.h
mov eax, 8 ; creat
mov ebx, filename ; first argument
mov ecx, 644O ; the suffix O means Octal in nasm, like the leading 0 in C. see: http://www.nasm.us/doc/nasmdoc3.html
int 80h ; calls the kernel
cmp eax, -1 ; creat returns -1 on error
je error
mov [fd], eax ; the return value is in eax - the file descriptor
; now, we'll write something to the file
; // man 2 write
; write(fd, hello_pointer, hello_length)
mov eax, 4 ; write
mov ebx, [fd],
mov ecx, hello
mov edx, hello_length
int 80h
cmp eax, -1
; it should also close the file in a normal program upon write error
; since it is open, but meh, since we just terminate the kernel
; will clean up after us
je error
; and now we close the file
; // man 2 close
; close(fd);
mov eax, 6 ; close
mov ebx, [fd]
int 80h
; and now close the program by calling exit(0);
mov eax, 1 ; exit
mov ebx, 0 ; return value
int 80h
error:
mov eax, 4 ; write
mov ebx, 1 ; write to stdout - file #1
mov ecx, error_message ; pointer to the string
mov edx, error_message_length ; length of the string
int 80h ; print it
mov eax, 1 ; exit
mov ebx, 1 ; return value
int 80h
如果您复制了上面的链接命令,该文件将被称为 a.out
。 ld 的 -o
选项改变了这一点。
我们还可以调用 C 函数,如果您需要写出数字等内容,这会很有帮助。
; nasm -f elf file.asm
; gcc -m32 file.o -nostdlib -lc # notice that we're using gcc to link, makes things a bit easier
; # the options are: -m32, 32 bit, -nostdlib, don't try to use the C lib cuz it will look for main()
; # and finally, -lc to add back some of the C standard library we want
BITS 32
; docs here: http://www.nasm.us/doc/nasmdoc6.html
; we declare the C functions as external symbols. the leading underscore is a C thing.
extern fopen
extern fprintf
extern fclose
section .data
; don't forget the 0 terminator if it akes a C string!
filename: db 'test.txt', 0
filemode: db 'wt', 0 ; the mode for fopen in C
format_string: db 'Hello with a number! %d is it.', 10, 0 ; new line and 0 terminator
; an error message to be printed with write(). The function doesn't
; use a C string so no need for a 0 here, but we do need length.
error_message: db 'Something went wrong.', 10 ; 10 == \n
; this next line means current location minus the error_message location
; which works out the message length.
; many of the system calls use pointer+length pairs instead of
; 0 terminated strings.
error_message_length: equ $ - error_message
fp: dd 0 ; this is like a global int variable in C
; global variables are generally a bad idea and there's other
; ways to do it, but for simplicity I'm using one here as the
; other ways are a bit more work in asm
section .text
global _start
_start:
; first, open or create the file. in C it would be:
; FILE* fp = fopen("text.txt", "wt");
; arguments for C functions are pushed on to the stack, right from left.
push filemode ; "wt"
push filename ; "text.txt"
call fopen
add esp, 8 ; we need to clean up our own stack. Since we pushed two four-byte items, we need to pop the 8 bytes back off. Alternatively, we could have called pop twice, but a single add instruction keeps our registers cleaner.
; the return value is in eax, store it in our fp variable after checking for errors
; in C: if(fp == NULL) goto error;
cmp eax, 0 ; check for null
je error
mov [fp], eax;
; call fprintf(fp, "format string with %d", 55);
; the 55 is just a random number to print
mov eax, 55
push eax ; all arguments are pushed, right to left. We want a 4 byte int equal to 55, so eax is it
push format_string
mov eax, [fp] ; again using eax as an intermediate to store our 4 bytes as we push to the stack
push eax
call fprintf
add esp, 12 ; 3 words this time to clean up
; fclose(fp);
mov eax, [fp] ; again using eax as an intermediate to store our 4 bytes as we push to the stack
push eax
call fclose
; the rest is unchanged from the above example
; and now close the program by calling exit(0);
mov eax, 1 ; exit
mov ebx, 0 ; return value
int 80h
error:
mov eax, 4 ; write
mov ebx, 1 ; write to stdout - file #1
mov ecx, error_message ; pointer to the string
mov edx, error_message_length ; length of the string
int 80h ; print it
mov eax, 1 ; exit
mov ebx, 1 ; return value
int 80h
这里还有很多事情可以做,比如一些消除这些全局变量的技术,或者更好的错误检查,甚至在汇编中编写 C 风格的 main() 。但这应该让您开始编写文本文件。提示:文件与写入屏幕相同,您只需要先打开/创建它们!
顺便说一句,不要同时混合系统调用和 C 库函数。 C 库(fprintf
等)缓冲数据,而系统调用则不缓冲数据。如果混合使用它们,数据最终可能会以令人惊讶的顺序写入文件。
代码类似,但 64 位略有不同。
最后,这个相同的模式可以用来将几乎任何 C 代码转换为 asm - 不同函数的 C 调用约定是相同的,并且带有参数放置等的 Linux 系统调用约定也遵循一致的模式。
进一步阅读: http://en.wikipedia.org/wiki/X86_calling_conventions#cdecl关于 C 调用约定
http://docs.cs.up.ac.za/programming/asm/derick_tut/syscalls.html在 Linux 系统调用上
What is the purpose of EBP in the following code?是我不久前写的关于 asm 中局部变量的另一个答案 - 这将暗示一种摆脱全局变量的方法,并描述 C 编译如何做到这一点。 (摆脱该全局的另一种方法是将 fd/fp 保留在寄存器中,并在需要释放寄存器以用于其他内容时将其压入或弹出到堆栈中)
以及每个函数的代码中引用的手册页。在 Linux 提示符下,执行 man 2 write
或 man 3 fprintf
等操作来查看更多信息。 (系统调用在手册第 2 节中,C 函数在手册第 3 节中)。
关于linux - 是否有在 NASM 中生成文本文本文件作为输出的程序示例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26951493/