0

I have been tasked with writing a NASM program that gets the day of the week for the first day of the next month. As an example: If today is June 4, then the program should say something like:

July 1st is a Thursday.

I am using the mktime function as well as a few other time/date functions. Here is my code:

extern time
extern localtime
extern exit
extern printf
extern mktime
extern ctime

global main

section .data

sSun: db "Sunday", 0
sMon: db "Monday", 0
sTue: db "Tuesday", 0
sWed: db "Wednesday", 0
sThu: db "Thursday", 0
sFri: db "Friday", 0
sSat: db "Saturday", 0

format_1: db "%d", 10, 0
string: db "%s", 10, 0

section .bss
timestamp: resd 1
tmstruct: resd 1

section .text
main:
pusha

push dword 0       ; fetch the timestamp
call time
add esp, 4
mov [timestamp], eax

push timestamp
call localtime
add esp, 4

;change the localtime struct to indicate first day of next month.

;seconds, minutes, hours, day of month from 1.
mov [eax], dword 0
mov [eax + 4], dword 0
mov [eax + 8], dword 0
mov [eax + 12], dword 1
;get month # from 0, to ecx.
mov ecx, [eax + 16]
cmp ecx, 11
jne notDecember

;its december. Set date to January of next year.
mov [eax + 16], dword 0
mov ecx, [eax + 20]
inc ecx
mov [eax + 20], ecx
jmp convertDate

notDecember:

;its not december, just move up the month by 1.
mov ecx, [eax + 16]
inc ecx
mov [eax + 16], ecx

convertDate:
mov [tmstruct], eax

;make a timestamp
;push tmstruct <-- Wrong
push dword [tmstruct] ; <-- Right
call mktime
add esp, 4

;move timestamp
mov [timestamp], eax

;make a new tm struct
push timestamp
call localtime
add esp, 4

;now we have the correct date, check the day of the week
mov ecx, [eax + 24]
push ecx ;<--- preserve this value or c function calls will trash it!

;do a ctime call
;push dword eax <-- Wrong
push timestamp ; <-- Right
call ctime
add esp, 4
push dword eax
push string
call printf
add esp, 8

pop ecx ;<--- pop preserved value!
push dword ecx
call dayOfWeek

popa
call exit


dayOfWeek:

cmp [esp + 4], dword 0
je pSun

cmp [esp + 4], dword 1
je pMon

cmp [esp + 4], dword 2
je pTue

cmp [esp + 4], dword 3
je pWed

cmp [esp + 4], dword 4
je pThu

cmp [esp + 4], dword 5
je pFri

cmp [esp + 4], dword 6
je pSat

push dword esp
push format_1
call printf
add esp, 8
push format_1
jmp endDow



pSun:
push sSun
jmp endDow

pMon:
push sMon
jmp endDow

pTue:
push sTue
jmp endDow

pWed:
push sWed
jmp endDow

pThu:
push sThu
jmp endDow

pFri:
push sFri
jmp endDow

pSat:
push sSat
jmp endDow

endDow:
push string
call printf
add esp, 8
ret 4

Basically, i am told that "The mktime function ignores the specified contents of the structure members tm_wday and tm_yday..." (from localtime tm struct) "....and recomputes them from the other information in the broken-down time structure."

Seeing this as the case, my plan was to create a tm structure for the current time, and simply modify all its elements to point to the first second of the first day of the next month, then use mktime on that. However, you will see that the program outputs the "hijacked" struct as "Wed Dec 31 18:00:59 1969", but then i even print out the day of the week from THAT and i get sunday. What have i done to go so wrong here?

Drifter64
  • 1,103
  • 3
  • 11
  • 30

2 Answers2

1

Ok, I took the C Sample mktime and modified it to do what you want:

extern printf, time, mktime, exit, localtime, scanf,strftime
global main
;~ int    tm_sec   Seconds [0,60]. 
;~ int    tm_min   Minutes [0,59]. 
;~ int    tm_hour  Hour [0,23]. 
;~ int    tm_mday  Day of month [1,31]. 
;~ int    tm_mon   Month of year [0,11]. 
;~ int    tm_year  Years since 1900. 
;~ int    tm_wday  Day of week [0,6] (Sunday =0). 
;~ int    tm_yday  Day of year [0,365]. 
;~ int    tm_isdst Daylight Savings flag. 

%define tm_sec 0
%define tm_min 4
%define tm_hour 8
%define tm_mday 12
%define tm_mon 16
%define tm_year 20
%define tm_wday 24
%define tm_yday 28
%define tm_isdst 32


section .bss
timeinfo    resd    1
rawtime     resd    1
lpszBuffer  resb    80

section .data
fmtdate     db  "%B %d %Y", 0

Sun         db  "Sunday", 0
Mon         db  "Monday", 0
Tue         db  "Tuesday", 0
Wed         db  "Wednsday", 0
Thu         db  "Thursday", 0
Fri         db  "Friday", 0
Sat         db  "Saturday", 0
WeekDay     dd  Sun, Mon, Tue, Wed, Thu, Fri, Sat

szThatDay   db  "%s is a %s", 10, 0

section .text
main: 

    ;~ Get todays date
    push    rawtime
    call    time 
    add     esp, 4 * 1

    push    rawtime
    call    localtime
    add     esp, 4 * 1

    mov     dword [timeinfo], eax

    ;~ Get current month and add one
    mov     edx, dword [eax + tm_mon] 
    inc     edx 
    ;~ move updated month back to structure 
    mov     dword [eax + tm_mon], edx

    ;~ set day to the first
    mov     dword [eax + tm_mday], 1 

    push    dword [timeinfo]
    call    mktime
    add     esp, 4 * 1

    push    dword [timeinfo]
    push    fmtdate
    push    80
    push    lpszBuffer
    call    strftime
    add     esp, 4 * 4

    mov     eax, dword [timeinfo]
    mov     eax, dword [eax + tm_wday]
    mov     ecx, dword [WeekDay + 4 * eax]
    push    ecx
    push    lpszBuffer
    push    szThatDay 
    call    printf
    add     esp, 4 * 3

    call    exit

Then to test, I displayed current date and ran the program which then showed the day of the week the 1st is of next month. I then changed the system clock and reran the test 2 more times. Test also worked under Windows.

enter image description here

Gunner
  • 5,780
  • 2
  • 25
  • 40
  • I see your answer. I would just like to try and make sure i understand this, maybe use it to modify my original code before i mark it off. Thank you for your reply! :) – Drifter64 Oct 04 '13 at 18:50
  • How is it possible that you increase the month number, even if its December, and that still works? You don't handle incrementing the year, and yet i clearly see a case in your output for December, and it works! – Drifter64 Oct 04 '13 at 19:33
  • The months are zero based in the magic land of the C Library, so `mov edx, dword [eax + tm_mon]` after the call to `time` and `localtime` return October (the current month) as 9, add one makes 10 which is November right? That would make December 11 add one to that and the month is 12, the code in the C Library knows the current year, and knows there is no month 12 so it is January of next year (IMO it works something like this since I haven't looked at the code for `mktime`) – Gunner Oct 05 '13 at 01:33
  • Gunner... i have tried to modify my code to take a similar approach to yours. I really want to actually understand this... and although your code works flawlessly, i need to be able to learn to write in my own way. I have taken most of my code and made equivalent statements to yours up to the point of the output to console, where i still use my dayOfWeek method. Somehow now it gives segfault, even though i balance my stack and dont think im accessing bad memory locations. May i contact you by your email, or could you help me here if i update my post to show current code? – Drifter64 Oct 17 '13 at 18:17
  • I found my problem. It seems some of the c functions trash my registers. Not sure why code from one of the most used languages would do such a thing! – Drifter64 Oct 21 '13 at 14:48
0

It seems i made a mistake in passing a value. Also, some of the c function calls seem to want to trash my values in the registers! Changes needed to run the code properly are commented with arrows.

Drifter64
  • 1,103
  • 3
  • 11
  • 30
  • Read this: http://en.wikipedia.org/wiki/X86_calling_conventions and pay attention to the section about the Intel ABI – Gunner Oct 22 '13 at 02:00
  • Yes, i am learning the hard way that certain values are trashed by protocol, while others are reserved. In NASM, the values are different to what you linked. They include EBX, ESI, EDI, and one other register which i forget. Of course, ESP is always preserved! ;) – Drifter64 Oct 30 '13 at 01:32