CMSC216 Assembly Review Exercise
CODE DISTRIBUTION: hw-review-asm-code.zip
- Download the code distribution every HW
- See further setup instructions below
CHANGELOG: Empty
Table of Contents
1 Review Problem 1
On a recent practice exam, an assembly version of the following C function was created.
// setday_fun.c: sample function to convert to assembly int DAYS_SINCE_1970; typedef struct { int day; int year; } yearday_t; int setday(yearday_t yd){ int day = yd.day; int year = yd.year; if(day < 0 || year < 1970){ DAYS_SINCE_1970 = -1; return 1; } int totaldays = day + (year - 1970)*365; DAYS_SINCE_1970 = totaldays; return 0; }
This function was demonstrated in a main()
function like the one
below.
// setday_main2.c: a sample main() that calls setday() #include <stdio.h> #include <stdlib.h> // global: days since 1/1/1970 extern int DAYS_SINCE_1970; // struct containing date info typedef struct { int day; int year; } yearday_t; // Layout of yearday_t in memory and // as a packed register argument. // // | | Byte | Byte | Packed | // | Field | Size | Offset | Bits | // |-------+------+--------+--------| // | day | 4 | +0 | 0-31 | // | year | 4 | +4 | 32-63 | int setday(yearday_t yd); int main(int argc, char *argv[]){ yearday_t yd2 = { .day = 3, .year = 1972 }; int ret = setday(yd2); printf("%3d days since 1970 (ret: %d)\n", DAYS_SINCE_1970, ret); // 733 days since 1970 (ret: 0) return 0; }
When compiled and run together, the output looks like the following
>> cd review-asm-code >> gcc setday_func.c setday_main2.c >> ./a.out 733 days since 1970 (ret: 0)
A good exercise is to convert this main()
into assembly as it
requires setting up a packed struct argument to a function.
There are two potnetial options for this:
- Place the struct in the stack and initialize its fields there, then load the struct into a register
- Directly place the struct in a register
Select one that seems right and complete the provided template version
of an assembly version of main()
.
### TEMPLATE for setday_main2_asm.s ### .data FORMAT: .string "%3d days since 1970 (ret: %d)\n" .text .global main main: ## grow the stack + align for function calls ## set up arg(s) and call setday function call ??? ## set up args and call printf@PLT function ## 3rd arg to printf: return value of setday ## 2nd arg to printf is DAYS_SINCE_1970 (global var) ## 1st arg to printf is FORMAT string address movl $0,%eax # requirement for printf and other var-arg functions call printf@PLT ## restore the stack and return from main
After completing your code, compile and run it to see if it matches the same behavior as the C version.
SOLUTION
Click for Solution
### SOLUTION for setday_main2_asm.s ### .data FORMAT: .string "%3d days since 1970 (ret: %d)\n" .text .global main main: subq $8,%rsp # grow the stack + align for function calls ## 2 METHODS to pack yearday_t struct into register rdi ## Method 1: place values in stack space, copy stack ## values into arg1 register movl $3,0(%rsp) # .day = 3 movl $1972,4(%rsp) # .year = 1972 movq 0(%rsp),%rdi ## ## Method 2: struct does not need to be in the stack for any ## ## reason so just directly pack the register. NOTE: cannot ## ## avoid extending the stack via subq $8,%rsp as rsp must be ## ## aligned to a 16-byte boundary for the function calls. ## movq $1972,%rdi ## salq $32,%rdi # upper 32 bits are .year ## orq $3,%rdi # lower 32 bits are .day call setday movl %eax,%edx # 3rd arg to printf: return value of setday movl DAYS_SINCE_1970(%rip),%esi # 2nd arg to printf (global var) leaq FORMAT(%rip),%rdi # 1st arg to printf: format string address movl $0,%eax # requirement for printf and other var-arg functions call printf@PLT addq $8,%rsp # restore the stack and return movl $0,%eax ret
NOTE: Either placing the struct in the stack then loading it (Method 1) OR directly packing a register with the fields of the struct (Method 2) will work in this case. GCC is likely to favor the latter as there is no reason to put the struct in memory. Both solutions would receive full credit if submitted by a student.
In other situations, the struct may need to be in memory such as if it needs a memory address. In that case, only Method 1 would work.