Assignment 3, Solutions

Part of the homework for 22C:112, Spring 2011
by Douglas W. Jones
THE UNIVERSITY OF IOWA Department of Computer Science

  1. Background: An assembler maps its input from one or more (source) files to an output (object) file by replacing various textual content in the input file(s), such as machine instruction names, with equivalent binary data such as the corresponding executable machine code. It allows textual names to be defined in terms of such things as machine addresses, and then it substitutes the actual addresses for those names.

    A linker maps its input from one or more (object) files to an output (executable) file by replacing various textual content in the input file(s), such as external symbol names, with equivalent binary data such as the corresponding external symbol values. It allows textual names to be defined in terms of such things as machine addresses, and then it substitutes the actual addresses for those names.

    A problem: (0.5 points) The above text suggests a strong parallel between what assemblers and linkers do. What (if anything) does an assembler do that a linker does not? What (if anything) does an linker do that an assembler does not? Focus on abstract functions!

    Since an assembler can be used to do most of what a linker does, and since a linker with a textual input language can be used to do most of what an assembler does, the only obvious answer is:

    Assemblers support comments and optional white space for the purpose of enhancing readability and documentation. Because object codes are designed as the output languages of assemblers and compilers, they rarely if ever contain any provisions for comments or optional white-space for the purpose of readability.

  2. Background: In the C standard library, FILE*s=fopen("myfile","r") opens a file named myfile for read access using the FILE pointer s. I can read successive characters of my file using ch=fgetc(s).

    The standard Unix system call int fd=open("myfile",O_RDONLY) opens a file named myfile for read access using the file descriptor fd. I can read successive characters of my file using read(fd,&ch,1)

    Obviously, the standard library layer is implemented in terms of the underlying Unix layer. System calls are inherently expensive, so the implementation of the C FILE abstraction makes an effort to call read infrequently using large buffers, so that calls to fgetc() usually simply get the next character from the buffer but occasionally call read() to get the next buffer.

    a) If performance were not an issue, give, in C a minimal representation for a C FILE variable, and give code for fgetc() written in terms of this minimal representation. Hint: This should involve writing trivial C code. (0.5 points)

    typedef FILE int;
    
    char fgetc( FILE * f ) {
            char ch;
            read( *f, &ch, 1 );
            return ch;
    }
    

    b) Suggest a reasonable reprsentation for a C FILE variable that supports the performance goals outlined above. (0.5 points)

    struct filestruct {
            int fd;
            char * ptr;
            char buf[BUFFLEN];
    }
    typedef FILE struct filestruct;
    

    c) Give C code for fgetc() written in terms of your reasonable representation. (0.5 points)

    char fgetc( FILE * f ) {
            char ch;
            if ( f->ptr >= f->buf + BUFFLEN ) {
                    read( f->fd, f->buf, BUFFLEN );
                    f->ptr = f->buf;
            }
            ch = * f->ptr;
            f->ptr ++;
            return ch;
    }
    

  3. Background: The standard Unix file interface involves open(), read(), write(), lseek() and close(), as well as some more obscure routines that we will ignore here. There is nothing object oriented about the design of this interface, yet at a conceptual level, an open file is a perfect example of an object.

    A Problem: How is the handle on an open-file object in Unix represented? What is the creator-initializer for open-file objects? What are the methods on an open file object, and if one of these is a destructor method, which?

    The handle is an integer file descriptor. The open() operator creates and initializes an open file object and returns its handle. The regular methods on an open file object are read(), write(), and lseek(). The close() method on an open file object is the object destructor.