Last Updated: 2025-05-15 Thu 13:24

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:

  1. Place the struct in the stack and initialize its fields there, then load the struct into a register
  2. 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.


Web Accessibility
Author: Chris Kauffman (profk@umd.edu)
Date: 2025-05-15 Thu 13:24