//---------------------------------------------------------------- // xmas.s // // This program shows which day-of-the-week is Christmas in // a year that is provided by a command-line argument. The // algorithm is based upon finding the number of days which // will have elapsed since 1900 (when Christmas occurred on // a Tuesday), and then performing a division by seven, the // number of days which occurs in any week. In calculating // the elapsed days it is necessary to take account of leap // years, which normally occur in years evenly divisible by // four, although years divisible by 100 are an exception. // // assemble using: $ as xmas.s -o xmas // and link using: $ ld xmas.o base10io.o -o xmas // // programmer: ALLAN CRUSE // written on: 07 FEB 2006 // revised on: 23 FEB 2007 -- to link with our 'base10io.o' //---------------------------------------------------------------- # manifest constants .equ dev_STDOUT, 1 .equ sys_WRITE, 4 .equ sys_EXIT, 1 .section .data param: .int 2007 # this year is a default radix: .int 10 # base of decimal system seven: .int 7 # number of days-per-week four: .int 4 # frequency of leap-years years: .int 0 # counts years since 1900 leaps: .int 0 # count of the leap-years days: .int 0 # elapsed days since 1900 theday: .int 0 # weekday number (0=Tues) daylst: .ascii "Tue,Wed,Thu,Fri,Sat,Sun,Mon," # names for days report: .ascii "xxx, Dec 25 \n" # message text to display replen: .int . - report # length of the message errmsg: .ascii "Year cannot be before 1900\n" # error-message errlen: .int . - errmsg # length of the message .section .text _start: call obtain_input # get the designated year call process_data # calculate Christmas day call print_output # display results to user jmp exit_program # return control to Linux obtain_input: cmpl $1, 4(%esp) # check: does argc == 1? je argx # yes, keep default value movl 12(%esp), %esi # get pointer to argv[1] call asc2eax # convert ascii to number movl %eax, param # save the argument-value cmpl $1900, param # check: param < 1900 ? jge argx # no, parameter accepted mov $sys_WRITE, %eax # system-call ID-number mov $dev_STDOUT, %ebx # device-file ID-number lea errmsg, %ecx # error-message address mov errlen, %edx # error-message length int $0x80 # invoke kernel service jmp exit_program # give control to Linux argx: ret # return to the caller exit_program: mov $sys_EXIT, %eax # system-call ID-number xor %ebx, %ebx # let zero be exit-code int $0x80 # invoke kernel service process_data: # compute the number of years since 1900 movl param, %eax # get the parameter value subl $1900, %eax # subtract the value 1900 movl %eax, years # store as count of years # compute the number of leap-years since 1900 movl years, %eax # get the number of years xorl %edx, %edx # extend dividend to long divl four # perform unsigned divide movl %eax, leaps # quotient counts leapyrs # compute the total number of days since 1900 movl $365, %eax # number of days-per-year mull years # times number of years addl leaps, %eax # plus the "extra" days movl %eax, days # gives days since 1900 # divide number of days by seven movl days, %eax # get the number of days xorl %edx, %edx # extended as a dividend divl seven # divide by days-in-week movl %edx, theday # remainder is day-of-week ret # return to caller print_output: # copy the day's name into our report-string mov theday, %esi # get day-number in ESI mov daylst(,%esi,4), %eax # lookup name in table mov %eax, report # put name into string # display our report on the day when Christmas occurs mov $sys_WRITE, %eax # system-call ID-number mov $dev_STDOUT, %ebx # device-file ID-number lea report, %ecx # message's address mov replen, %edx # message's length int $0x80 # invoke kernel service ret .global _start # make entry-point visible .end # nothing more to assemble