ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
I have a problem. I adapt a simple program in ASM to write to a file a text string and it writes in binary information. Where is the problem?
Here is the code:
Code:
.include "linux.s"
.include "record-def.s"
.section .data
.equ ST_FILE_DESCRIPTOR, -4
record1:
.ascii "Hey diddle diddle!\0"
#This is the name of the file we will write to
file_name:
.ascii "heynow.txt\0"
.globl _start
_start:
#Copy the stack pointer to %ebp
movl %esp, %ebp
#Allocate space to hold the file descriptor
subl $4, %esp
#Open the file
movl $SYS_OPEN, %eax
movl $file_name, %ebx
movl $0101, %ecx #This says to create if it doesn't exist, and open for writing
movl $0666, %edx
int $LINUX_SYSCALL
#Store the file descriptor away
movl %eax, ST_FILE_DESCRIPTOR(%ebp)
#Write the first record
pushl ST_FILE_DESCRIPTOR(%ebp)
pushl $record1
call write_record
addl $8, %esp
#Close the file descriptor
movl $SYS_CLOSE, %eax
movl ST_FILE_DESCRIPTOR(%ebp), %ebx
int $LINUX_SYSCALL
#Exit the program
movl $SYS_EXIT, %eax
movl $0, %ebx
int $LINUX_SYSCALL
.equ RECORD_SIZE, 18
#PURPOSE: This function writes a record to
# the given file descriptor
#
#INPUT: The file descriptor and a buffer
#
#OUTPUT: This function produces a status code
#
#STACK LOCAL VARIABLES
.equ ST_WRITE_BUFFER, 8
.equ ST_FILEDES, 12
.section .text
.globl write_record
.type write_record, @function
write_record:
pushl %ebp
movl %esp, %ebp
pushl %ebx
movl $SYS_WRITE, %eax
movl ST_FILEDES(%ebp), %ebx
movl ST_WRITE_BUFFER(%ebp), %ecx
movl $RECORD_SIZE, %edx
int $LINUX_SYSCALL
#NOTE - %eax has the return value, which we will
#give back to our calling program
popl %ebx
movl %ebp, %esp
popl %ebp
ret
Let's see...
First off, the null terminator is not necessary in your record1 (especially since you don't include it in your RECORD_SIZE)
What do you mean by "it writes in binary information". When I try it, it works fine. If you try
Code:
mypromptislongorcolorful$ file heynow.txt
heynow.txt: ASCII text, with no line terminators
mypromptislongorcolorful$ cat heynow.txt
mypromptislongorcolorful$ngorcolorful$
^
The only thing weird is that there is no newline at the end of the string. This means that "cat heynow.txt" will output the contents and probably be overwritten by your shell prompt. The location of the cursor is probably where the carrot mark is shown. All you need to do to remedy this is put a "\n" (newline) at the end of record1. Then make your RECORD_SIZE 19.
I mean, if I assemble it with as, then link it with ld, it writes a binary file not a normal text file ...
There is no fundamental difference between a "text" file and a "binary" file (a better way to say this is that a text file is a special kind of binary file). Did you try adding the newline? What's the output when you do "file heynow.txt"? How about the output when you do "hexdump -C heynow.txt"?
Well, it works now, but im looking to simplify the program. I added the newline so it works now good. It was a binary file beacause I filled accidentaly 300 bytes full of zero after the string so it read the file as binary.
Right, it works. How could I simplify the program? On what parts?
I guess I didn't understand the point of write_record. Will it be used when repeatedly writing records to a file? If so, are you guaranteed that each record is exactly RECORD_SIZE bytes in length? Usually when you are guaranteeing a specific number of bytes each time, your output should be "binary" (for example the contents of a struct or something). Second, the RECORD_SIZE would most likely remain fixed (e.g., to the size of the struct). But you are outputting an ASCII string. In order to keep RECORD_SIZE constant, you'd need to make record1 "Hey diddle diddle\n" (i.e., replace the exclamation point).
The other thing that I find complicated is the file structure and style. I would recommend using macros instead of memory for constants (i.e., C style macros with gcc and the .S suffix) in your header files. More importantly, why do you include the record-def.s file if you intend for write_record to be a standalone function (which I assume after the first paragraph ). If it's not a standalone-function, does it become a useless wrapper for write()?
So I guess the short version is, why are you writing ASCII data with a fixed size record-writing function? If it's not a fixed-size record-writing function, what is it?
Well, baiscly it's none of that. It is just a simple ASM program to write to a file a certain text. That's all. What do you think, how can I simplify it?
Notice how with #define macros, the end-product doesn't have extra symbols (i.e., SYS_OPEN, SYS_WRITE, etc.) floating around. You don't have to retabulate the syscall numbers, as that's already done in /usr/include/asm/unistd.h. The variable holding the length of record1 will automatically change as you change the size of the string. Additionally, since you have so few variables, you don't need to put the file descriptor on the stack, and you don't have the overhead of an extra function call.
Well, I understand what you say, thanks a lot. It is my first time writing in ASM so I am studying the Book Programming from the Ground Up. That is why I used as and ld. But as I see now it is easyer to do it as you did, even compiled with gcc.
...I used as and ld. But as I see now it is easyer to do it as you did, even compiled with gcc.
Just a quick point: "compiling" with gcc (in the way I did) is not any different from using gas (which is actually called by gcc behind the scenes), except for the processing of C-style macros, which are more readable/convenient (at least to me) than .macro and .endm.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.