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
Related
I am currently learning a bit of Assembler on Linux and I need your advice.
Here is the small program:
.section .data
zahlen:
.float 12,44,5,143,223,55,0
.section .text
.global _start
_start:
movl $0, %edi
movl zahlen (,%edi,4), %eax
movl %eax, %ebx
begin_loop:
cmpl $0, %eax
je prog_end
incl %edi
movl zahlen (,%edi,4), %eax
cmpl %ebx, %eax
jle begin_loop
movl %eax, %ebx
jmp begin_loop
prog_end:
movl $1, %eax
int $0x80
The program seems to compiling and running fine.
But I have some unclear questions/behaviors:
if I check the return value, which is the highers number in register %ebx, with the command "echo %?" it always return 0. I expect the value 223.
Any Idea why this happens?
I checked with DDD and gdb compiling with debugging option. So i saw that the program runs the correct steps.
But if i want to exam the register with command ie. "i r eax" it only shows me the address i believe, not the value. Same on DDD. I see only registers rax rbx and so on.
Here i need some advise to get on the right track.
Any Help appreciated.
Thanks
The "main" registers eax, ebx, ecx, edx, etc. are all designed to work with integers only. A float is a shorthand term that typically refers to a very specific data format (namely, the IEEE-754 binary32 standard), for which your CPU has dedicated registers and hardware to work with. As you saw, you are allowed to load them into integer registers as-is, but the value isn't going to convert itself like it would in a high-level, dynamically-typed language. Your code loaded the raw bit pattern instead, which likely is not at all what you intended.
This is because assembly has no type safety or runtime type-checking. The CPU has no knowledge of what type you declared your data as in your program. So when loading from memory into eax the CPU assumes that the data is a 32-bit integer, even if you declared it in your source code as something else.
If you're curious as to what a float actually looks like you can check this out: Floating Point to Hex Calculator
Switching from float to long solved the problem. Think mistake by myself. Also compiling and linking as 32bit shows the right registers in the debugger.
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.
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
I am reading some linux assembly manuals and found idea about using printf() function. I need it to output register values for debugging reasons in binary form to terminal, but now I am tried simply to test that function with text.
I am stuck, because of segfault when I am using pushq instead of pushl. How can I change this program to output strings and binary form of registers?
.data
input_prompt:
.string "Hello, world!"
printf_format:
.string "%5d "
printf_newline:
.string "\n"
size:
.long 0
.text
.globl main
main:
pushq $input_prompt
call printf
movl $0, %eax
ret
It was compiled by GCC as:
gcc tmp.S -o tmp
Linux (and Windows) x86-64 calling convention has the first few arguments not on the stack, but in registers instead
See http://www.x86-64.org/documentation/abi.pdf (page 20)
Specifically:
If the class is MEMORY, pass the argument on the stack.
If the class is INTEGER, the next available register of the sequence %rdi, %rsi, %rdx, %rcx, %r8 and %r9 is used.
If the class is SSE, the next available vector register is used, the registers are taken in the order from %xmm0 to %xmm7.
If the class is SSEUP, the eightbyte is passed in the next available eightbyte chunk of the last used vector register.
If the class is X87, X87UP or COMPLEX_X87, it is passed in memory.
The INTEGER class is anything that will fit in a general purpose register, so that's what you would use for string pointers as well.
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