How to rewrite a files content? Linux x86_64, assembly, GAS - linux

Hi ive got this exciting task, almost done actually.. but it fails in a funny aspect.
The mission is to load a file with integers, sort them and write them to a file. Yay... Well my program is doing that, but it keeps the original content. ie:
lets say
45
32
Should get the ordered content
32 45
Well my program is keeping the original content and adds the new:
45 32 32 45.
So any sugestions on solving this? Though of deleting the original file and creating a new one in the same name. But thats kinda a failure, if the file has non-integers and my code has error reporting about that.
Ill give the important code here:
_OpenFile:
movq $2, %rax # open file
movq $inputfile, %rdi # filename
movq $2, %rsi # read and write
movq $0644, %rdx # setting proper permissions
syscall
ret
And:
_PrintNumber: #needs rdi as numberholder
movq $1, %r9 # count the number of chars to print
push $10 # store the chars on the stack, we always have '\n'
movq %rdi, %rax # things are easier with it in rax
movq $10, %rcx
decode_loop:
movq $0, %rdx
idivq %rcx # do rdx:rax / rcx
addq $48, %rdx # convert the remainder to an ASCII digit
pushq %rdx # and save it on the stack
addq $1, %r9 # while counting the number of chars
cmpq $0, %rax
jne decode_loop # loop until rax == 0
write_loop:
movq $1, %rax # write
movq $3, %rdi # to the file
movq %rsp, %rsi # which is stored here
movq $1, %rdx # a single character/byte
syscall
addq $8, %rsp # pop the character
addq $-1, %r9 # correct the char count
jne write_loop # loop until r9 reaches 0
ret
Thanks to all who would like to comment this!

It looks like you're either re-opening the file with O_APPEND, or you opened it read/write and didn't seek to the beginning before rewriting it. (So after reading the whole file, the position of the file descriptor is the end of the file, so newly-written data will go there.)
The lseek(2) system call is what you need to move the file position. lseek(fd, 0, SEEK_SET) rewinds to the beginning. (Args go in EDI, RSI, EDX, like normal for the x86-64 System V system-call convention, and the kernel interface matches the libc interface.)
Since the data you'll be writing out has the same length, you don't need to ftruncate(fd, len) the file before you start rewriting. You will overwrite all the bytes all the way to the end.
And BTW, you don't need to write each character separately; you can make a small buffer containing all the ASCII bytes for a number and make one write system call; much more efficient and actually takes less code: Printing an integer as a string with AT&T syntax, with Linux system calls instead of printf. My answer there also shows that you can #include <asm/unistd.h> and use code like
mov $__NR_write, %eax # SYS_write, from unistd_64.h
instead of using numeric literals for the system-call numbers, if you use a .S file so gcc will run it through the preprocessor.
Unfortunately, most headers like <unistd.h> (not asm/unistd.h) have C declarations as well, so you can't as easily get macros for constants like SEEK_SET or O_RDWR that would let you do mov $SEEK_SET, %edx or mov $O_WRONLY|O_CREAT|O_TRUNC, %esi.
Unlinking the file would have no effect on the contents of the already-open file; to get an effect like what you're picturing in the question, you could close/reopen the file. (In Unix, removing the directory entry for a file doesn't affect programs that already have it open. It will be freed from disk once the last directory entry and file-descriptor for it are gone, though.)
So you'd open it for reading, read all the data, and then (after checking for errors, when you're sure you have some valid data to write), open(infile, O_CREAT|O_TRUNC|O_WRONLY, 0666) and write out data. You didn't use O_APPEND, so the position of the new write-only FD will be at the front of the file. And the file-size will be truncated to 0. Exactly like echo foo > filename in the shell.
(It will still have the same inode number and be "the same file" with different contents unless you unlink(infile) before opening it to re-create a new file of that name. In that case O_CREAT is actually necessary. When reopening an existing file to write + truncate, O_CREAT isn't needed when the file already exists.)
The key here is to check for read errors before doing anything destructive, not just read it, destroy the original, and then continue on. So the file is still there on disk while you're sorting.

Related

How do I use "nanosleep" in x86 Assembly?

I have some problems with Linux' nanosleep syscall. This code should wait 2 seconds before it exits, but it doesn't:
.text
.globl _start
_start:
pushq %rbp
movq %rsp,%rbp
pushq $0 #0 nanoseconds
pushq $2 #2 seconds
leaq (%rbp),%rdi #the time structure on the stack
movq $35,%rax #nanosleep syscall
movq $0,%rsi #disable useless parameter
syscall
leave
After pushing stuff on the stack, use mov %rsp, %rdi. RSP (the current stack pointer) is what's pointing to your newly-pushed struct, not RBP (the frame pointer). lea (%rsp), %rdi is a less-efficient way to write that, but would also work.
You're passing RBP as the pointer, but it still points to the saved RBP value from making a "stack frame". Note that is _start, not a function, so you're really just terminating the linked list of saved-RBP values. The System V ABI recommends doing this by explicitly setting RBP to zero, but Linux zeros registers (other than RSP) on process startup so this works.
Anyway, at _start, (rsp) is argc, and then you push a 0 (the saved RBP) and set RBP to point there. So the struct you're passing to sys_nanosleep is {0, argc}. Or argc nanoseconds. (Test with strace to see if I got this right; I didn't try it.)
This is what you should do:
pushq $0 #0 nanoseconds
pushq $2 #2 seconds
### RSP instead of RBP in the next instruction:
mov %rsp, %rdi #the time structure we just pushed
mov $35, %eax #SYS_nanosleep
xor %esi, %esi #rem=NULL, we don't care if we wake early
syscall
# RSP is 16 bytes lower than it was before this fragment, in case that matters for later code.
I also optimized by not using 64-bit operand-size when you don't need it (because writing a 32-bit register zeros the upper 32 bits). I like letting register sizes imply operand size instead of using movq, like in Intel syntax. I also used the idiomatic way to zero a register, and improving the comments.
Your proposed answer is broken: subq $16, %rbp before leave is bad idea.
If you want to address your newly-pushed struct relative to your RBP stack frame, you could lea -16(%rbp), %rdi.
But modifying %rbp will make leave set RSP to the updated RBP and then pop the low qword of the struct into RBP, instead of the caller's saved RBP. RSP is left pointing to the high qword of your struct, rather than the function return address.
This probably only works because you just use sys_exit after leave, because you're not in a function so you couldn't ret anyway. It makes no sense to use leave in _start, because it's not a function. You have to just sys_exit or sys_exit_group.
But if you used this fragment inside an actual function, it would break the stack.
I figured it out on myself. This works:
#call nanosleep
movq $35,%rax
subq $16, %rbp
movq %rbp,%rdi
movq $0,%rsi
syscall
leave

read and write to file assembly

I have an inputfile.txt which looks like this: 3 4 2 0 8 1 5 3
I'm trying to write inside an outputfile.txt each character of inputfile incremented by 1.
So inside outputfile.txt I should see 4 5 3 1 9 2 6 4.
I have tried to write this piece of code but I have several doubts.
.section .data
buff_size: .long 18
.section .bss
.lcomm buff, 18
.section .text # declaring our .text segment
.globl _start # telling where program execution should start
_start:
popl %eax # Get the number of arguments
popl %ebx # Get the program name
popl %ebx # Get the first actual argument - file to read
# open the file
movl $5, %eax # open
movl $0, %ecx # read-only mode
int $0x80
# read the file
movl $0, %esi
movl %eax, %ebx # file_descriptor
analyzecharacter: #here I want to read a single character
movl $3, %eax
movl $buff, %edi
leal (%esi,%edi,1), %ecx
movl $1, %edx
int $0x80
add $1, %esi #this point is not clear to me, what I'd like to do is to increment the index of the buffer in order to be positioned on the next cell of buffer array, I've added 1 but I think is not correct
cmp $8, %esi # if I've read all 8 characters then I'll exit
je exit
openoutputfile:
popl %ebx # Get the second actual argument - file to write
movl $5, %eax # open
movl $2, %ecx # read-only mode
int $0x80
writeinoutputfile:
#increment by 1 and write the character to STDOUT
movl %eax, %ebx # file_descriptor
movl $4, %eax
leal (%esi,%edi,1), %ecx
add $1, %ecx #increment by 1
movl $1, %edx
int $0x80
jmp analyzecharacter
exit:
movl $1, %eax
movl $0, %ebx
int $0x80
I have 2 problems/doubts:
1- my first doubt is about this instruction: add $1, %esi. Is this the right way to move through buffer array?
2- The second doubt is: When I analyze each character should I always invoke openoutputfile label? I think that in this way I'm reopening the file and the previous content is overwritten.
Indeed if I run the program I see only a single character \00 (a garbage character, caused by the value of %esi in this instruction I guess: leal (%esi,%edi,1), %ecx ).
I hope my problems are clear, I'm pretty new to assembly and I've spent several hours on this.
FYI:
I'm using GAS Compiler and the syntax is AT&T.
Moreover I'm on Ubuntu 64 bit and Intel CPU.
So, how I would do the code...
Thinking about it, I'm so used to Intel syntax, that I'm unable to write AT&T source from my head on the web without bugs (and I'm too lazy to actually do the real thing and debug it), so I will try to avoid writing instructions completely and just describe the process, to let you fill up the instructions.
So let's decide you want to do it char by char, version 1 of my source:
start:
; verify the command line has enough parameters, if not jump to exitToOs
; open both input and output files at the start of the code
processingLoop:
; read single char
; if no char was read (EOF?), jmp finishProcessing
; process it
; write it
jmp processingLoop
finishProcessing:
; close both input and output files
exitToOs:
; exit back to OS
now "run" it in your mind, verify all the major branch points make sense and will handle correctly for all major corner cases.
make sure you understand how the code will work, where it will loop, and where and why it will break out of loop.
make sure there's no infinite loop, or leaking of resources
After going trough my checklist, there's one subtle problem with this design, it's not rigorously checking file system errors, like failing to open either of the files, or writing the character (but your source doesn't care either). Otherwise I think it should work well.
So let's extend it in version 2 to be more close to real ASM instructions (asterisk marked instructions are by me, so probably with messed syntax, it's up to you to make final version of those):
start:
; verify the command line has enough parameters, if not jump to exitToOs
popl %eax # Get the number of arguments
* cmpl $3,eax ; "./binary fileinput fileoutput" will have $3 here?? Debug!
* jnz exitToOs
; open both input and output files at the start of the code
movl $5, %eax # open
popl %ebx # Get the program name
; open input file first
popl %ebx # Get the first actual argument - file to read
movl $0, %ecx # read-only mode
int $0x80
cmpl $-1, %eax ; valid file handle?
jz exitToOs
* movl %eax, ($varInputHandle) ; store input file handle to memory
; open output file, make it writable, create if not exists
movl $5, %eax # open
popl %ebx # Get the second actual argument - file to write
* ; next two lines should use octal numbers, I hope the syntax is correct
* movl $0101, %ecx # create flag + write only access (if google is telling me truth)
* movl $0666, %edx ; permissions for out file as rw-rw-rw-
int $0x80
cmpl $-1, %eax ; valid file handle?
jz exitToOs
movl %eax, ($varOutputHandle) ; store output file handle to memory
processingLoop:
; read single char to varBuffer
movl $3, %eax
movl ($varInputHandle), %ebx
movl $varBuffer, %ecx
movl $1, %edx
int $0x80
; if no char was read (EOF?), jmp finishProcessing
cmpl $0, %eax
jz finishProcessing ; looks like total success, finish cleanly
;TODO process it
* incb ($varBuffer) ; you wanted this IIRC?
; write it
movl $4, %eax
movl ($varOutputHandle), %ebx # file_descriptor
movl $varBuffer, %ecx ; BTW, still set from char read, so just for readability
movl $1, %edx ; this one is still set from char read too
int $0x80
; done, go for the next char
jmp processingLoop
finishProcessing:
movl $0, ($varExitCode) ; everything went OK, set exit code to 0
exitToOs:
; close both input and output files, if any of them is opened
movl ($varOutputHandle), %ebx # file_descriptor
call closeFile
movl ($varInputHandle), %ebx
call closeFile
; exit back to OS
movl $1, %eax
movl ($varExitCode), %ebx
int $0x80
closeFile:
cmpl $-1, %ebx
ret z ; file not opened, just ret
movl $6, %eax ; sys_close
int $0x80
; returns 0 when OK, or -1 in case of error, but no handling here
ret
.data
varExitCode: dd 1 ; no idea about AT&T syntax, "dd" is "define dword" in NASM
; default value for exit code is "1" (some error)
varInputHandle: dd -1 ; default = invalid handle
varOutputHandle: dd -1 ; default = invalid handle
varBuffer: db ? ; (single byte buffer)
Whoa, I actually wrote it fully? (of course it needs the syntax check + cleanup of asterisks, and ";" for comments, etc...)
But I mean, the comments from version 1 were already so detailed, that each required only handful of ASM instructions, so it was not that difficult (although now I see I did submit the first answer 53min ago, so this was about ~1h of work for me (including googling and a bit of other errands elsewhere)).
And I absolutely don't get how some human may want to use AT&T syntax, which is so ridiculously verbose. I can easily understand why the GCC is using it, for compilers this is perfectly fine.
But maybe you should check NASM, which is "human" oriented (to write only as few syntax sugar, as possible, and focus on instructions). The major problem (or advantage in my opinion) with NASM is Intel syntax, e.g. MOV eax,ebx puts number ebx into eax, which is Intels fault, taking LD syntax from other microprocessors manufacturers, ignoring the LD = load meaning, and changing it to MOV = move to not blatantly copy the instruction set.
Then again, I have absolutely no idea why ADD $1,%eax is the correct way in AT&T (instead of eax,1 order), and I don't even want to know, but it doesn't make any sense to me (the reversed MOV makes at least some sense due to LD origins of Intel's MOV syntax).
OTOH I can relate to cmp $number,%reg since I started to use "yoda" formatting in C++ to avoid variable value changes by accident in if (compare: if (0 = variable) vs if (variable = 0), both having typo = instead of wanted == .. the "yoda" one will not compile even with warnings OFF).
But ... oh.. this is my last AT&T ASM answer for this week, it annoys hell out of me. (I know this is personal preference, but all those additional $ and % annoys me just as much, as the reversed order).
Please, I spend serious amount of time writing this. Try to spend serious time studying it, and trying to understand it. If confused, ask in comments, but it would be pitiful waste of our time, if you would completely miss the point and not learn anything useful from this. :) So keep on.
Final note: and search hard for some debugger, find something what suits you well (probably some visual one like old "TD" from Borland in DOS days would be super nice for newcomer), but it's absolutely essential for you to improve quickly, to be able to step instruction by instruction over the code, and watch how the registers and memory content do change values. Really, if you would be able to debug your own code, you would soon realize you are reading second character from wrong file handle in %ebx... (at least I hope so).
Just to clear 1) early: add $1, %esi is indeed equivalent to inc %esi.
While you are learning assembler, I would go for the inc variant, so you don't forget about its existence and get used to it. Back in 286-586 times it would be also faster to execute, today the add is used instead - because of the complexity of micro architecture (μops), where inc is tiny fraction more complicated for CPU (translating it back to add μops I guess, but you shouldn't worry about this while learning basics, aim rather for "human" readability of the source, do not any performance tricks yet).
Is it the right way?
Well, you should firstly decide whether you want to parse it per character (or rather go for byte, as character is nowadays often utf8 glyph, which can have size from 1 to 6 or how many bytes; I'm not even sure) OR to process it with buffers.
Your mix of the two is making it easy to do additional mistakes in the code.
From a quick look I see:
you read only single byte per syscall, yet you store it at new place
in buffer+counter (why? Just use single byte buffer, if you work per byte)
when counter is 8, you exit (not processing the 8th
read byte at all).
you lose forever your input file descriptor after opening output file first time by popl %ebx (leaking file handles is very bad)
then second char is read from output file (reusing the file handle from write)
then you popl %ebx again, but there's no third parameter on command line, i.e. you fetch undefined memory from stack
indeed you reopen the output file each time, so unless it's in append mode, it will overwrite content.
That's probably all major blunders you did, but that's actually so many, that I would suggest you to start over from scratch.
I will try to do a quick my version in next answer (as this one is getting a bit long), to show you how I would do it. But at first please try (hard) to find all the points I did highlight above, and understand how your code works. If you will fully understand what your instructions do, and why they really do the error I described, you will have much easier time to design your next code, plus debugging it. So the more of the points you will really find, and fully understand, the better for you.
"BTW notes":
I never did linux asm programming (I'm now itching to do something after reading about your effort), but from some wiki about system calls I read:
All registers are preserved during the syscall.
Except return value in eax of course.
Keep this in mind, it may save you some hassle with repeating register setup before call, if you group syscalls appropriately.

x86 Assembly (Linux) stdin read syscall returning 1 with no data input

When I compare $0 against %eax for error checking, and enter no input when prompted, the error message does not display. However, when I compare $1 against %eax and enter no input, the error message displays. I'm aware that a read syscall returns the amount of bytes read into %eax, although I'm unsure as to why it returns a byte was read when no input is given, the man pages also don't give me any indication to why this is the case. Is stdin input null-terminated or is it something else?
movl $3, %eax
movl $0, %ebx
movl $BUFFER, %ecx
movl $BUFFER_SIZE, %edx
int $0x80
cmpl $0, %eax
jle input_error
If cmpl $0 is changed to cmpl $1, and no input is given, it jumps to input_error, with cmpl $0 program flow proceeds when no input is given.
You can't call sys_read with these parameters and to expect that there will be no input.
sys_read is blocking call. So, it will block until some input appears. In your case, IMO, you press ENTER and in this case, sys_read returns with 1 byte read in the buffer - LF, ascii code 0Ah and eax=1.
P.S. It is not my job, but better use FASM or at least NASM. This way you will get much more help in your ASM programming. GAS has really terrible syntax. :)

Linux sbrk() as a syscall in assembly

So, as a challenge, and for performance, I'm writing a simple server in assembly. The only way I know of is via system calls. (through int 0x80) Obviously, I'm going to need more memory than allocated at assemble, or at load, so I read up and decided I wanted to use sbrk(), mainly because I don't understand mmap() :p
At any rate, Linux provides no interrupt for sbrk(), only brk().
So... how do I find the current program break to use brk()? I thought about using getrlimit(), but I don't know how to get a resource (the process id I'd guess) to pass to getrlimit(). Or should I find some other way to implement sbrk()?
The sbrk function can be implemented by getting the current value and subtracting the desired amount manually. Some systems allow you to get the current value with brk(0), others keep track of it in a variable [which is initialized with the address of _end, which is set up by the linker to point to the initial break value].
This is a very platform-specific thing, so YMMV.
EDIT: On linux:
However, the actual Linux system call returns the new program break on success. On failure, the system call returns the current break. The glibc wrapper function does some work (i.e., checks whether the new break is less than addr) to provide the 0 and -1 return values described above.
So from assembly, you can call it with an absurd value like 0 or -1 to get the current value.
Be aware that you cannot "free" memory allocated via brk - you may want to just link in a malloc function written in C. Calling C functions from assembly isn't hard.
Source:
#include <unistd.h>
#define SOME_NUMBER 8
int main() {
void *ptr = sbrk(8);
return 0;
}
Compile using with Assembly Output option
gcc -S -o test.S test.c
Then look at the ASM code
_main:
Leh_func_begin1:
pushq %rbp
Ltmp0:
movq %rsp, %rbp
Ltmp1:
subq $16, %rsp
Ltmp2:
movl $8, %eax
movl %eax, %edi
callq _sbrk
movq %rax, -16(%rbp)
movl $0, -8(%rbp)
movl -8(%rbp), %eax
movl %eax, -4(%rbp)
movl -4(%rbp), %eax
addq $16, %rsp
popq %rbp
ret
Leh_func_end1:
There is no system call for it but you should be able to still make the call

How to manipulate strings with x86 assembly?

I'm in the process of writing an assembly program that takes two strings as input and concatenates them. Here's what I have: (using NASM syntax)
SECTION .data
hello: db "Hello ",0
world: db "world!",0
SECTION .text
; do the concatenation
Since I've never done any work with strings in x86 assembly before, I need to know how storing and manipulating strings work in the first place.
I'm guessing that once the length of each string is known, that concatenating would simply involve moving chunks of memory around. This part can be simplified by using libc. (I can use strlen() and strcat().)
My real problem is that I'm not familiar with the way strings are stored in x86 assembly. Do they just get added to the stack...? Do they go on a heap somewhere? Should I use malloc() (somehow)?
The strings in your example are stored the same way a global character array would be stored by a C program. They're just a series of bytes in the data section of your executable. If you want to concatenate them, you're going to need some space to do it - either do it on the stack, or call malloc() to get yourself some memory. As you say, you can just use strcat() if you are willing to call out to libc. Here's a quick example I made (AT&T syntax), using a global buffer to concatenate the strings, then print them out:
.data
hello:
.asciz "Hello "
world:
.asciz "world!"
buffer:
.space 100
.text
.globl _main
.globl _puts
.globl _strcat
_main:
push %rbp
mov %rsp, %rbp
leaq buffer(%rip), %rdi
leaq hello(%rip), %rsi
callq _strcat
leaq buffer(%rip), %rdi
leaq world(%rip), %rsi
callq _strcat
leaq buffer(%rip), %rdi
callq _puts
mov $0, %rax
pop %rbp
retq

Resources