• No results found

Example: Mapping File into Memory

In document Low Level Programming (Page 79-82)

■ Question 48 read about meaning of the fourth ( 08:01 ) and fifth ( 144225 ) column in man procfs

4.9 Example: Mapping File into Memory

We need another system call, namely, open. It is used to open a file by name and to acquire its descriptor.

See Table 4-2 for details.

Table 4-2. open System Call

REGISTER VALUE MEANING

rax 2 System call identifier

rdi file name Pointer to a null-terminated string, name.holding file

rsi flags A combination of permission flags (read only, write only, or both).

rdx mode If sys open is called to create a file, it will hold its file system permissions.

Mapping file in memory is done in three simple steps:

• Open file using open system call. rax will hold file descriptor.

• Call mmap with relevant arguments. One of them will be the file descriptor, acquired at step 1.

• Use print_string routine we have created in Chapter 2. For the sake of brevity we omit file closing and error checks.

4.9.1 Mnemonic Names for Constants

Linux was written in C, so to ease interaction with it some useful constants are predefined in a C way. The line

#define NAME 42

defines a substitution performed in compile time. Whenever a programmer writes NAME, the compiler substitutes it with 42. This is useful to create mnemonic names for various constants. NASM provides similar functionality using

%define directive

%define NAME 42

See section 5.1 “Preprocessor” for more details on how such substitutions are made.

Let’s take a look at a man page for mmap system call, describing its third argument prot.

The prot argument describes the desired memory protection of the mapping (and must not conflict with the open mode of the file). It is either PROT_NONE or the bitwise OR of one or more of the following flags:

PROT_EXEC Pages may be executed.

PROT_READ Pages may be read.

PROT_WRITE Pages may be written.

PROT_NONE Pages may not be accessed.

PROT_NONE and its friends are examples of such mnemonic names for integers used to control mmap behavior. Remember that both C and NASM allow you to perform compile-time computations on constant values, including bitwise AND and OR operations. Following is an example of such computation:

%define PROT_EXEC 0x4

%define PROT_READ 0x1

mov rdx, PROT_READ | PROT_EXEC

Unless you are writing in C or C++, you will have to check these predefined values somewhere and copy them to your program.

Following is how to know the specific values of these constants for Linux:

1. Search them in header files of the Linux API in /usr/include.

2. Use one of the Linux Cross Reference (lxr) online, like: http://lxr.free-electrons.com.

We do recommend the second way for now, as we do not know C yet. You may even use a search engine like Google and type lxr PROT_READ as a search query to get relevant results immediately after following the first link.

For example, here is what LXR shows when being queried PROT_READ:

PROT_READ

Defined as a preprocessor macro in:

arch/mips/include/uapi/asm/mman.h, line 18 arch/xtensa/include/uapi/asm/mman.h, line 25 arch/alpha/include/uapi/asm/mman.h, line 4 arch/parisc/include/uapi/asm/mman.h, line 4 include/uapi/asm-generic/mman-common.h, line 9

By following one of these links you will see

18 #define PROT_READ 0x01 /* page can be read */

So, we can type %define PROT_READ 0x01 in the beginning of the assembly file to use this constant without memorizing its value.

4.9.2 Complete Example

Create a file test.txt with any contents and then compile and launch the file listed in Listing 4-4 in the same directory. You will see file contents written to stdout.

Listing 4-4. mmap.asm

; These macrodefinitions are copied from linux sources

; Linux is written in C, so the definitions looked a bit

; different there.

; We could have just looked up their values and use

; them directly in right places

; However it would have made the code much less legible

%define O_RDONLY 0

%define PROT_READ 0x1

%define MAP_PRIVATE 0x2 section .data

; This is the file name. You are free to change it.

fname: db 'test.txt', 0 section .text

global _start

; These functions are used to print a null terminated string print_string:

; mmap

mov r8, rax ; rax holds opened file descriptor ; it is the fourth argument of mmap mov rax, 9 ; mmap number

mov rdi, 0 ; operating system will choose mapping destination mov rsi, 4096 ; page size

mov rdx, PROT_READ ; new memory region will be marked read only mov r10, MAP_PRIVATE ; pages will not be shared

mov r9, 0 ; offset inside test.txt

syscall ; now rax will point to mapped location mov rdi, rax

call print_string

mov rax, 60 ; use exit system call to shut down correctly xor rdi, rdi

syscall

4.10 Summary

In this chapter we have studied the concept and the implementation of virtual memory. We have elaborated it as a particular case of caching. Then we have reviewed the different types of address spaces (physical, virtual) and the connection between them through a set of translation tables. Then we dived into the virtual memory implementation details.

Finally, we have provided a minimal working example of the memory the mapping using Linux system calls. We will use it again in the assignment for Chapter 13, where we will base our dynamic memory allocator on it. In the next chapter we are going to study the process of translation and linkage to see how an operating system uses the virtual memory mechanism to load and execute programs.

In document Low Level Programming (Page 79-82)