NASM: Получение дня недели с другой датой
Мне было поручено написать программу NASM, которая получает день недели для первого дня следующего месяца. Как пример: если сегодня 4 июня, то программа должна сказать что-то вроде:
July 1st is a Thursday.
Я использую функцию mktime, а также несколько других функций времени / даты. Вот мой код:
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
По сути, мне говорят, что "функция mktime игнорирует указанное содержимое членов структуры tm_wday и tm_yday..." (из локального времени tm struct) ".... и пересчитывает их из другой информации в разбитой структуре времени ".
Исходя из этого, я планировал создать структуру tm для текущего времени и просто изменить все ее элементы так, чтобы они указывали на первую секунду первого дня следующего месяца, а затем использовать mktime для этого. Тем не менее, вы увидите, что программа выводит "угнанную" структуру как "Wed Dec 31 18:00:59 1969", но затем я даже распечатываю день недели из THAT, и я получаю воскресенье. Что я сделал, чтобы пойти не так здесь?
2 ответа
Кажется, я допустил ошибку при передаче значения. Кроме того, некоторые вызовы функций c, похоже, хотят уничтожить мои значения в регистрах! Изменения, необходимые для правильной работы кода, отмечены стрелками.
Хорошо, я взял образец mktime C и изменил его, чтобы сделать то, что вы хотите:
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
Затем, чтобы проверить, я отобразил текущую дату и запустил программу, которая затем показала день недели, 1-го числа следующего месяца. Затем я изменил системные часы и повторил тест еще 2 раза. Тест также работал под Windows.