2013-10-01 15 views
0

Мне поручено написать программу NASM, которая получит день недели в первый день следующего месяца. В качестве примера: если сегодня 4 июня, то программа должна сказать что-то вроде:NASM: Получение дня недели в другую дату

July 1st is a Thursday. 

Я использую функцию, а указываете ей также несколько других функций времени/даты. Вот мой код:

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 

В принципе, я сказал, что «функция игнорирует указываете ей заданное содержимое структуры членов tm_wday и tm_yday ...» (из LocalTime тм структуры)».... и пересчитывает их от другой информации в структуре разбитого времени ».

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

ответ

0

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

+0

Прочтите это: http://en.wikipedia.org/wiki/X86_calling_conventions и обратите внимание на раздел о Intel ABI – Gunner

+0

Да, я изучаю жесткий способ, что определенные значения обрываются протоколом, в то время как другие зарезервированы. В NASM значения отличаются от того, с чем вы связаны. Они включают EBX, ESI, EDI и еще один регистр, который я забыл.Конечно, ESP всегда сохраняется! ;) – Drifter64

1

Хорошо, я взял 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.

enter image description here

+0

Я вижу ваш ответ. Я просто хотел бы попробовать и убедиться, что я понимаю это, возможно, использовать его для изменения моего исходного кода, прежде чем я его помет. Спасибо за ваш ответ! :) – Drifter64

+0

Как можно увеличить число месяцев, даже если его декабрь и все еще работает? Вы не обрабатываете прирост года, и все же я четко вижу случай в вашем выпуске в декабре, и он работает! – Drifter64

+0

Месяцы основаны на нулевом значении в волшебной стране библиотеки C, поэтому «mov edx, dword [eax + tm_mon]» после вызова «time» и «localtime» возвращают октябрь (текущий месяц) в 9, добавляют один составляет 10, что в ноябре? Это заставило бы 11 декабря добавить один к этому, а месяц - 12, код в C-библиотеке знает текущий год, и знает, что нет месяца 12, так что это январь следующего года (IMO это работает примерно так, так как я раю 't посмотрел код для 'mktime') – Gunner

Смежные вопросы