Consider this GNU Assembler program, that copies one byte at a time from stdin to stdout, with a delay of one second between each:
#include <sys/syscall.h>
.global _start
_start:
movq $1, -16(%rsp)
movq $0, -8(%rsp)
movl $1, %edx
.again:
xorl %edi, %edi
leaq -17(%rsp), %rsi
movl $SYS_read, %eax
syscall
cmpq $1, %rax
jne .end
leaq -16(%rsp), %rdi
xorl %esi, %esi
movl $SYS_nanosleep, %eax
syscall
movl $1, %edi
leaq -17(%rsp), %rsi
movl $SYS_write, %eax
syscall
jmp .again
.end:
xorl %edi, %edi
movl $SYS_exit_group, %eax
syscall
It passes pointers to the red zone to syscalls, for both inputs and outputs, and also expects the rest of the red zone to be preserved across unrelated syscalls. Is this a safe use of the red zone that's guaranteed to always work, or is it UB that just happened to appear to work in my test?
Is this a safe use of the red zone that's guaranteed to always work, or is it UB that just happened to appear to work in my test?
It's guaranteed to be safe by the kernel developers.
In general (to guard against deliberately malicious software) CPUs are designed so that when you switch from a lower privilege level (user-space) to a higher privilege level (kernel) the CPU forces a stack switch (e.g. from "untrusted user-space stack" to "more trusted kernel stack"); and CPU also does the reverse (switching stacks when returning from higher privilege level to lower privilege level).
This makes it easy for kernel developers to ensure that system calls (and IRQs, etc) don't interfere with a user-space thread's red zone; but it doesn't necessarily prevent a kernel from interfering with a user-space thread's red zone (a kernel could do extra work for no reason to interfere, if the kernel developer wanted their kernel to be awful).
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.
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
We are working on an educational operating system called Pintos, trying to set it up to support Virtualization. We start with the version running on 32 bits and our first step would be to switch to 64bit mode and continue from there.
We're running Pintos via Bochs.
We have looked up the steps to do this in Intel Programmer's Manual ( chapter 9.8.5, volume 3) and when we want to set the IA32 EFER.LME bit to 1, in order to enable IA32e mode, the system generates a triple fault and starts working from the beginning once again.
Here's the code we've been working on.
#Step 1: Disable paging CR0_PG = 0. Use MOV CR0 instr. to disable paging (instr. must be located in an identity-mapped page.
movl %cr0, %eax
andl $0x7fffffff, %eax
movl %eax, %cr0
#Step 2: Enable physical-address extensions by setting CR4_PAE = 1
movl %cr4, %eax
orl $CR4_PAE, %eax
movl %eax, %cr4
#Step 3: Load CR3 with the physical base address of the level 4 page map table PML4
movl $0xe000, %eax
movl %eax, %cr3
xchg %bx, %bx
#Step 4: Enable IA-32e mode by setting IA32_EFER_LME = 1
movl $0xc0000080, %ecx
rdmsr
or $IA32_EFER_LME, %eax
wrmsr
#Step 5: Enable paging CR0_PG = 1.
movl %cr0, %eax
orl $CR0_PG, %eax
movl %eax, %cr0
We've tried setting up our own TSS because out of all the possible cases suggested by Intel that may generate a triple fault, this one seemed the only reasonable cause.
Any ideas why the triple fault is being generated? All seems clear and the steps are followed, still the kernel panic attack occurs.
We have finally managed to solve this annoying problem. It turned out that the virtual machine we used to emulate Pintos, bochs, was not configured to run on 64-bit mode. Once the correct configurations have been made, it worked on the first try.
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
I ran gcc -S over this:
int main()
{
printf ("Hello world!");
}
and I got this assembly code:
.file "test.c"
.section .rodata
.LC0:
.string "Hello world!"
.text
.globl main
.type main, #function
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $20, %esp
movl $.LC0, (%esp)
call printf
addl $20, %esp
popl %ecx
popl %ebp
leal -4(%ecx), %esp
ret
.size main, .-main
.ident "GCC: (GNU) 4.3.0 20080428 (Red Hat 4.3.0-8)"
.section .note.GNU-stack,"",#progbits
I am curious to understand this output. Can someone share some pointers in understanding this output, or if someone could mark comments against each of these lines/group of lines explaining what it does it would be great.
Here how it goes:
.file "test.c"
The original source file name (used by debuggers).
.section .rodata
.LC0:
.string "Hello world!"
A zero-terminated string is included in the section ".rodata" ("ro" means "read-only": the application will be able to read the data, but any attempt at writing into it will trigger an exception).
.text
Now we write things into the ".text" section, which is where code goes.
.globl main
.type main, #function
main:
We define a function called "main" and globally visible (other object files will be able to invoke it).
leal 4(%esp), %ecx
We store in register %ecx the value 4+%esp (%esp is the stack pointer).
andl $-16, %esp
%esp is slightly modified so that it becomes a multiple of 16. For some data types (the floating-point format corresponding to C's double and long double), performance is better when the memory accesses are at addresses which are multiple of 16. This is not really needed here, but when used without the optimization flag (-O2...), the compiler tends to produce quite a lot of generic useless code (i.e. code which could be useful in some cases but not here).
pushl -4(%ecx)
This one is a bit weird: at that point, the word at address -4(%ecx) is the word which was on top of the stack prior to the andl. The code retrieves that word (which should be the return address, by the way) and pushes it again. This kind of emulates what would be obtained with a call from a function which had a 16-byte aligned stack. My guess is that this push is a remnant of an argument-copying sequence. Since the function has adjusted the stack pointer, it must copy the function arguments, which were accessible through the old value of the stack pointer. Here, there is no argument, except the function return address. Note that this word will not be used (yet again, this is code without optimization).
pushl %ebp
movl %esp, %ebp
This is the standard function prologue: we save %ebp (since we are about to modify it), then set %ebp to point to the stack frame. Thereafter, %ebp will be used to access the function arguments, making %esp free again. (Yes, there is no argument, so this is useless for that function.)
pushl %ecx
We save %ecx (we will need it at function exit, to restore %esp at the value it had before the andl).
subl $20, %esp
We reserve 32 bytes on the stack (remember that the stack grows "down"). That space will be used to storea the arguments to printf() (that's overkill, since there is a single argument, which will use 4 bytes [that's a pointer]).
movl $.LC0, (%esp)
call printf
We "push" the argument to printf() (i.e. we make sure that %esp points to a word which contains the argument, here $.LC0, which is the address of the constant string in the rodata section). Then we call printf().
addl $20, %esp
When printf() returns, we remove the space allocated for the arguments. This addl cancels what the subl above did.
popl %ecx
We recover %ecx (pushed above); printf() may have modified it (the call conventions describe which register can a function modify without restoring them upon exit; %ecx is one such register).
popl %ebp
Function epilogue: this restores %ebp (corresponding to the pushl %ebp above).
leal -4(%ecx), %esp
We restore %esp to its initial value. The effect of this opcode is to store in %esp the value %ecx-4. %ecx was set in the first function opcode. This cancels any alteration to %esp, including the andl.
ret
Function exit.
.size main, .-main
This sets the size of the main() function: at any point during assembly, "." is an alias for "the address at which we are adding things right now". If another instruction was added here, it would go at the address specified by ".". Thus, ".-main", here, is the exact size of the code of the function main(). The .size directive instructs the assembler to write that information in the object file.
.ident "GCC: (GNU) 4.3.0 20080428 (Red Hat 4.3.0-8)"
GCC just loves to leave traces of its action. This string ends up as a kind of comment in the object file. The linker will remove it.
.section .note.GNU-stack,"",#progbits
A special section where GCC writes that the code can accommodate a non-executable stack. This is the normal case. Executable stacks are needed for some special usages (not standard C). On modern processors, the kernel can make a non-executable stack (a stack which triggers an exception if someone tries to execute as code some data which is on the stack); this is viewed by some people as a "security feature" because putting code on the stack is a common way to exploit buffer overflows. With this section, the executable will be marked as "compatible with a non-executable stack" which the kernel will happily provide as such.
Here is some supplement to #Thomas Pornin's answer.
.LC0 local constant, e.g string literal.
.LFB0 local function beginning,
.LFE0 local function ending,
The suffix of these label is a number, and start from 0.
This is gcc assembler convention.
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $20, %esp
these instructions don't compare in your c program, they're always executed at the beginning of every function (but it depends on compiler/platform)
movl $.LC0, (%esp)
call printf
this block corresponds to your printf() call. the first instruction places on the stack its argument (a pointer to "hello world") then calls the function.
addl $20, %esp
popl %ecx
popl %ebp
leal -4(%ecx), %esp
ret
these instructions are opposite to the first block, they're some sort of stack manipulation stuffs. always executed too