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 localtime) «… и пересчитывает их из другой информации в разбитой временной структуре. ."

Учитывая это, я планировал создать структуру tm для текущего времени и просто изменить все ее элементы, чтобы они указывали на первую секунду первого дня следующего месяца, а затем использовать для этого mktime. Однако вы увидите, что программа выводит «захваченную» структуру как «Среда, 31 декабря, 18:00:59 1969», но затем я даже распечатываю день недели из ЭТОГО и получаю воскресенье. Что я сделал, чтобы пойти так неправильно здесь?


person Drifter64    schedule 01.10.2013    source источник


Ответы (2)


Хорошо, я взял пример C mktime и изменил его, чтобы он делал то, что вы хотите:

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.

введите здесь описание изображения

person Gunner    schedule 04.10.2013
comment
Я вижу твой ответ. Я просто хотел бы попытаться убедиться, что я понимаю это, может быть, использовать его для изменения моего исходного кода, прежде чем я его отмечу. Спасибо за ваш ответ! :) - person Drifter64; 04.10.2013
comment
Как возможно, что вы увеличиваете номер месяца, даже если это декабрь, и это все еще работает? Вы не обрабатываете увеличение года, и все же я ясно вижу случай в вашем выводе за декабрь, и это работает! - person Drifter64; 04.10.2013
comment
Месяцы нулевые, основанные на волшебной стране библиотеки C, поэтому mov edx, dword [eax + tm_mon] после вызова time и localtime возвращают октябрь (текущий месяц) как 9, прибавляя единицу, получается 10, то есть ноябрь, верно? Это сделало бы 11 декабря добавленным к этому, а месяц - 12, код в библиотеке C знает текущий год и знает, что месяца 12 нет, поэтому это январь следующего года (ИМО, это работает примерно так, так как я не не смотрел код для mktime) - person Gunner; 05.10.2013
comment
Стрелок... я попытался изменить свой код, чтобы использовать подход, аналогичный вашему. Я действительно хочу понять это... и хотя ваш код работает безупречно, мне нужно научиться писать по-своему. Я взял большую часть своего кода и сделал эквивалентные вам операторы вплоть до вывода на консоль, где я все еще использую свой метод dayOfWeek. Каким-то образом теперь это дает segfault, хотя я балансирую свой стек и не думаю, что я обращаюсь к плохим ячейкам памяти. Могу ли я связаться с вами по электронной почте, или вы могли бы помочь мне здесь, если я обновлю свой пост, чтобы показать текущий код? - person Drifter64; 17.10.2013
comment
Я нашел свою проблему. Кажется, что некоторые из функций c уничтожают мои регистры. Не уверен, почему код одного из наиболее часто используемых языков может делать такие вещи! - person Drifter64; 21.10.2013

Кажется, я сделал ошибку при передаче значения. Кроме того, некоторые вызовы функций c, похоже, хотят уничтожить мои значения в регистрах! Изменения, необходимые для правильной работы кода, отмечены стрелками.

person Drifter64    schedule 21.10.2013
comment
Прочитайте это: en.wikipedia.org/wiki/X86_calling_conventions и обратите внимание на раздел о Intel ABI - person Gunner; 22.10.2013
comment
Да, я на собственном горьком опыте узнаю, что некоторые значения удаляются протоколом, а другие зарезервированы. В NASM значения отличаются от того, что вы связали. Они включают EBX, ESI, EDI и еще один регистр, о котором я забыл. Конечно, ESP всегда сохраняется! ;) - person Drifter64; 30.10.2013