180 likes | 193 Views
The ‘system-call’ ID-numbers. How can Linux applications written in assembly language create and access files?. A Modern OS Design. Application. Application. Application. Shared Runtime Libraries. user-mode. supervisor-mode. System Call Interface. memory manager. process manager.
E N D
The ‘system-call’ ID-numbers How can Linux applications written in assembly language create and access files?
A Modern OS Design Application Application Application Shared Runtime Libraries user-mode supervisor-mode System Call Interface memory manager process manager file manager network manager Device Driver Components OS Kernel Hardware
Role of ‘runtime libraries’ • To understand what role is played by the kernel’s interface with ‘runtime libraries,’ let’s see how we could go around them. • We can create a demo-program that does not need to use the standard C library – it will perform all their work on its own. • If you fire your janitor, you will very quickly come to appreciate all that he did for you!
Apps can call kernel directly Assembly Language application C application C++ application Shared Runtime Libraries user-mode supervisor-mode System Call Interface memory manager process manager file manager network manager Device Driver Components OS Kernel Hardware
Standard C library functions • The functions ‘write()’ and ‘exit()’ were not actually defined within our program-code • They are examples of ‘external’ functions • Header-files let the compiler know how to generate assembler code that calls them • Their actual definitions are part of the standard GNU/C runtime-library (‘glibc’) • The linker connects our code to ‘glibc’
The function ‘prototypes’ ssize_t write( int fd, void * buf, size_t count ); void exit( int status ); The C/C++ compiler needs this information to correctly generate the machine-code for calls to these ‘external’ library-functions.
C/C++ type names • Some data-types used in C and C++ have sizes that are dependent on the underlying CPU architecture and OS design, and are not identical for all platforms and compilers • A few relevant examples: • ‘long int’ • ‘size_t’ • ‘ssize_t’ • ‘off_t’
POSIX • The ‘Portable Operating System Interface’ • Defines a conformance ‘standard’ that lets application programmers write code which is ‘portable’ across differing architectures • Implemented with header-files and shared runtime libraries • Documented as an ANSI standard • Online reference available via ‘man’ pages
Frequently needed functions • Here are a few of the POSIX standard functions which are most frequently used by applications: • open() • read() • write() • close() • lseek() • exit() • It’s advisable to learn them! (will save you time)
Their C function-prototypes ssize_t read( int fd, void *buf, size_t count ); ssize_t write( int fd, void *buf, int count ); int open( char *fname, int flags, … ); int close( int fd ); off_t lseek( int fd, off_t offset, int whence ); void exit( int status ); NOTE: These POSIX functions correspond directly to Linux kernel system-calls
Linux x86_64 system-call IDs • All the Linux system-calls are assigned ID-numbers in this header-file: </usr/src/linux/include/asm/unistd_64.h> // System-call examples for x86_64 Linux #define __NR_read 0 #define __NR_write 1 #define __NR_open 2 #define __NR_close 3 … #define __NR_lseek 8 … #define __NR_exit 60 …
function semantics • We will give a rough general description of the actions taken by the kernel when these six frequently needed functions are called • Additional details about each function can be found online, using the ‘man’ command • Example: $ man 2 read
ssize_t write( int fd, void *buf, size_t count ) • This function asks the kernel to transfer ‘count’ bytes from the array pointed to by ‘buf’ to the previously-opened file specified by the file-descriptor ‘fd’. • If the kernel cannot transfer any bytes, it returns the value -1; otherwise it returns the number of bytes that the kernel was able to transfer successfully and advances the file-pointer accordingly.
ssize_t read( int fd, void *buf, size_t count ) • This function asks the kernel to transfer ‘count’ bytes into the array pointed to by ‘buf’ from the previously-opened file specified by ‘fd’. • If the kernel cannot transfer any bytes, it returns a value of -1 -- unless the file-pointer is already at the end of the file; otherwise, it returns the number of bytes successfully transferred and advances the file-pointer accordingly.
int open( char *fname, int flags, … ) • This function asks the kernel to set up an internel record establishing a connection between the file named ‘fname’ and an unused nonnegative integer known as a file-descriptor, provided the file’s access permissions allow the kind of access that is specified by the ‘flags’ argument • The function returns -1 if it cannot perform this operation; otherwise, it returns the file-descriptor value. • An additional argument when creating a new file
int close( int fd ) • This function asks the kernel to remove the connection it had previously set up between the file-descriptor ‘fd’ and the internal kernel record of an associated file. • The value -1 is returned if the kernel was not succesful in performing this operation (e.g., the file had already been closed); otherwise, this function returns 0.
off_t lseek( int fd, off_t offset, int whence) • This function asks the kernel to reposition the offset of the open file associated with the file descriptor ‘fd’ to the position given as ‘offset’ according to the given ‘whence’ directive, as follows: • SEEK_SET (=0): position is set to ‘offset’ • SEEK_CUR (=1): position += ‘offset’ • SEEK_END (=2): position = EOF + ‘offset’
void exit( int status ) • This function asks the kernel to terminate the current program, and place the value of ‘status’ into the internal record that the kernel had associated with this program when it was first launched. • This function will not return any value (because it does not return at all!)