This lab should be done with an assigned partner. Here is the lab3 partner list.
First run update31, which will create the directory structure for your lab 3 assignment and copies over some starting point files:
$ update31 $ cd cs31/labs/03 $ pwd /home/your_user_name/cs31/labs/03Use the Makefile included in the starting point code!
Your first task is to use bitwise operations to dissect two integers into their component bits to compare the count of "on" bits between the two values. In the file named bits.c implement a function named bitCompare that given two ints a and b, returns:
Modify the main function in bits.c to make a call to your bitCompare function. Test out your function. Make sure it works for all combinations of positive, zero, and negative input values. You can use gdb to print out binary representations of integers to verify that your function is doing the right thing (remember gdb does not print out leading zeros):
(gdb) p/t (int)(1234) (gdb) p/t (int)(-1234)to compare, and print out the result of the bit-compare of the two values. Here are a few runs of a working program (yours does not need to print out the exact same positive and negative values as mine, but should print out a positive or negative when mine does):
./bits usage: ./bits a b ./bits 7 8 bit compare result of 7(0x7) and 8(0x8) is 2 ./bits -7 12 bit compare result of -7(0xfffffff9) and 12(0xc) is 28 ./bits 4 6 bit compare result of 4(0x4) and 6(0x6) is -1 ./bits 10 6 bit compare result of 10(0xa) and 6(0x6) is 0
(based on an assignment written by Julie Zelenski)
Bit vectors are often used to represent a set of (on/off or true/false) values in a space-efficient way. In a bit vector each individual bit represents the presence or absence of a particular value in the set. In this assignment you are going to encode and decode bit vectors that are used to maintain permission information associated with each Unix file.
Associated with every Unix file is a set of users (u:owner, g:group, o:other). With each user is a set of file access permissions (r: read, w: write, x:execute). In addition, a Unix file can be either a regular file or a directory. You can see file permissions in Unix by running ls -l. For example:
$ ls -l -rw------- 1 newhall users 0 Sep 12 11:18 blah.c -rw-r--r-- 1 newhall users 20 Sep 12 11:17 foo.c drwxr-x--- 3 newhall users 4096 Sep 10 13:19 inclass/ drwx------ 4 newhall users 4096 Sep 10 13:19 labs/This shows that blah.c and foo.c are regular files, and inclass and labs are directories (the d bit is set). It also shows the permissions for the three different groups in the following order (a dash means that the corresponding permission for a particular user is not granted):
directory owner group other linkcount owner group bytes date filename --------- ----- ----- ----- --------- ----- ----- ----- ---- -------- d rwx rwx rwx - rw- r-- r-- 1 newhall users 200 ... foo.cThe ls -l output above shows that the owner of the files (newhall), has read and write access to every file and directory listed, and execute access to the two directories (execute access is required to cd into a directory). The group (users) has read access to foo.c and read and execute access to inclass. And, all other users have read access to file foo.c.
To encode these 10 permission values in a bit vector requires two bytes of space (an unsigned short). The low-order 10 bits of the short value are used to encode the 10 values, the high-order 6 bits are unused:
unsigned short bit-vector: -------------------------------------------- | high-order byte | low-order byte | -------------------------------------------- bit: 15 ... 10 9 8|7 6 5 4 3 2 1 0 unused d r|w x r w x r w x owner group otherThe chmod command can be used to change the permission on a file. For example:
chmod 640 foo.cgives the owner read and write permission on foo.c, group read permission, and other no permissions (6 is 110 in binary corrsponding to 1 for the owner's read permission bit, 1 for the owner's write permission bit, and 0 for the owner's execute permission bit).
In a file named, filepermissions.c, you will implement two functions that encode and decode file permission bit vectors:
The first 4 parameters are 4 int values representing the permissions: the first for the directory bit (a 0 or 1 value); the second for the owner permissions (0-7 value); the third for the group permissions (0-7 value); and the fourth for other permissions (0-7 value). The fifth parameter is an unsigned short passed by reference that the function will fill with the bit-vector encoding of the file permissions.
d rwx rwx rwxFor example, if the bit vector encodes that the owner has read and write permission and that group has read permission, you would set the string parameter's contents to be:
- rw- r-- ---
./fileperms ERROR: usage: ./fileperms dir_bit owner_perm group_perm other_perm ./fileperms 2 9 3 1 ERROR: invalid permission inputs dir:2 owner:9 group:3 other:1 dir must be (0:1), rest must be (0:7)....try again ./fileperms 1 7 5 5 encoding 1 7 5 5 is: 1005 (0x3ed) the permission encoding of 0x3ed is: d rwx r-x r-x ./fileperms 0 6 4 0 encoding 0 6 4 0 is: 416 (0x1a0) the permission encoding of 0x1a0 is: - rw- r-- ---
For this part, you will starting with this file and editing it in vim to add content, incuding comments, stack contents, and a likely C-code translation of the IA32 instructions. In particular, do the following:
00: movl $0x3,-0x4(%ebp) # store value 3 at mem location %ebp-4 # (x <-- 3) 01: shll $0x2,-0x4(%ebp) ...(notice how I added another comment line between the two instructions to avoid line wrapping that is caused by lines longer than 80 characters)
Stack ===== esp--> y: x: 3(00) ebp-->If x's value is changed later, let's say at instruction 34 x is set to 7, I'd add the following:
x: 3(00), 7(34)After tracing through the code, the y: and x: lines should show a history of how those stack locations are changed by executing the IA32 instructions (showing the value(instruction_number) pair of each change).
void swap(int *x, int *y);For this part you will start with one of the file's you copied over, swap.s. This file already contains some code IA32 instructions that set up up and tear down the stack frame associated with the swap function. You will add IA32 instructions to the body of this IA32 function that perform the swapping operation.
main.c contains code to test our your swap function.
The Makefile has a rule to build an executable named swap from main.c and swap.s.
esp ----> # swap's stack frame: ebp ----> # main's stack frame: ebp+0x8: first parameter value ebp+0xc: second parameter value
# re-cast address as an int pointer (int *), then dereference the pointer * (gdb) *(int *)(0x1234)
Once you are satisfied with your solutions, hand them in by typing handin31 at the unix prompt.
Only one of you or your partner should run handin31 to submit your joint solutions If you accidentally both run it, send me email right away letting me know which of the two solutions I should keep and which I should discard (you don't want the grader to just guess which joint solution to grade).
You may run handin31 as many times as you like, and only the most recent submission will be recorded. This is useful if you realize, after handing in some programs, that you'd like to make a few more changes to them.