התגובות שלי בפורום
-
מאתתגובות
-
Idan Dorמשתתף
הי תומר
3) אני ממליץ על הדיבאגר שיואב כתבנו https://forum.codeguru.co.il/wp/?topic=silenterrors-debugger הוא קצת לא מעודכן אבל ממש נוח.
2) זה כן, אני משאר שפשוט לא שינית את ה ES שלך, ממליץ להסתכל בעזרת הדיבאגר.
1) אני לא יודע איך זה ב NASM אבל ב FASM (מה שאני רגיל אליו) ובאחרים פשוט עושים mov di, exit בהנחה ש exit זה קבוע או label.עידן
Idan Dorמשתתףאוקיי, קודם כל כמה הערות כלליות:
1) מומלץ להשתמש פשוט בשורה
mov cx,(exit-start + 1)/2
כדי להפוך את cx לגודל הנכון.
2) אני ממליץ לך להשתמש ב assembler בשם fasm, שבו אתה לא צריך לרשום את הדברים בתחילת הקוד שלך ואתה יכול פשוט לרשום את הקוד.
3) כדי לאפס אוגר מסוים, אפשר לחסוך בית בכך שעושים לו xor עם עצמו במקום לעשות אליו mov 0.עכשיו לגבי למה הקוד שלך מת, מיקומים בזיכרון (כלומר, אוגרים בסוגריים מרובעות) מתוכנתים ברמה הבינארית כך:
000 : DS:[BX+SI]
•001 : DS:[BX+DI]
•010 : SS:[BP+SI]
•011 : SS:[BP+DI]
•100 : DS:[SI]
•101 : DS:[DI]
•110 : SS:[BP]
•111 : DS:[BX]
כלומר, כאשר אתה מנסה לגשת למיקום [di] כפי שאתה עושה, בגלל החלפת הסגמנטים שלך אתה מנסה לגשת למיקום di באזור המשותף שהוא כמובן מחוץ לתחום ולכן אתה מת.עכשיו, כדי לגרום לקוד שלך לעבוד אתה צריך לעשות את השינויים הבאים:
העברת החלפת הסגמנטים לאחרי לולאת ההפצצה.
הורדת השורה mov di, 500, אין לי שמץ של מושג למה אתה מריץ אותה, בגללה אתה מעתיק קוד לאמצע es במקום לתחילתו (ואחר כך אתה מנסה לקרוא מתחילת האזור המשותף עם si מאופס). במקום השורה הזאת אתה צריך לשים את השורה xor di, di שתאפס את di לאחר הקפיצה הראשונה שלך.
לאחר שתעשה את שתי השונויים האלו הקוד שלך יעבוד.Idan Dorמשתתףכפי שתוכל לראות אם פשוט תכתוב את השורד הבא:
push es
push ds
pop es
pop ds
jmp $ניתן להחליף בין הסגמנטים בעזרת push ו pop, וזה מה שכל שורד שהחליף סגמנטים עושה מאז השנה הראשונה של התחרות. במילים אחרות יש לך טעות אחרת בקוד ואין בעיה בחלק הזה בקוד (אם אתה מת בו זה בגלל משהו במקום אחר), אם תפרסם את הקוד אני יוכל לעזור.
עידןIdan Dorמשתתףבמובן הבסיסי כן, אבל לא בדיוק. תזכור שלא כל פקודה היא באורך של בית אחד בלבד, כלומר, אם אתה רוצה להריץ פקודה ארוכה מבית אחד אתה צריך כמה movsw לפני כן.
לדוגמא, השורד bash מהשנה מריץ במשך הרבה זמן מזמן הריצה שלו את הפקודות pushf ו movsw. בגלל שאורך הפקודה pushf היא בית אחד אז אפשר שכל פקודה שנייה תיהיה movsw.
לעומת זאת, אם אתה רוצה להריץ את הפקודה mov ax, 0x1234 אז אתה צריך שלושה פקודות movsw לפני כן (ופקודת movsw אחרי) כי אורך הפקודה הוא 3 בתים.
דוגמא נוספת:
אם תסתכל בקוד של שורד שפרסמתי בדף "בדיקה האם עליתי על עצמי" שהוא הדף הבא, אז תוכל לראות שרשמתי את הפקודה movsw כמה פעמים ברצף לפני קוד הקפיצה כי קוד הקפיצה חייב להיות לא מפורק (כי הוא משנה את di) ולכן צריך להעתיק את כולו לפני הרצתו.Idan Dorמשתתףכתיבה לאקסטרא סגמנט וקריאה מהאקטרה סגמנט זה בעצם כמעט אותו הדבר. movsw תמיד מעתיק שתי בתים מ ds:si ל es:di כלומר, אם נחליף את הסגמנטים es ו ds נאפס את si ונשנה את di למקמונו הנוכחי +1 הפקודה movsw תעתיק את שתי הבתים הראשונים ב es לאחרי ה movsw.
כמובן שדבר כזה מעתיק רק שני בתים אז צריך לדאוג לכך שלפחות אחד משני הבתים האלו הוא גם movsw ובסופו של דבר צריך לאפס שוב את si כי אחרת הוא יצא מהאזור שמותרת לך גישה אליו וכו.
אבל באופן הבסיסי זה פשוט איך שאמרתי בהתחלה.Idan Dorמשתתףמניסיוני אין דרך טובה יותר ללמוד מאשר לנסות להבין קוד כזה.
כמה הסברים לעזרה:
Movsw- אחת הפקודות הכי שימושיות בתחרות הזאתי בגלל כמות הדברים שהיא עושה. באופן כללי היא מעתיקה שתי בתים בזיכרון ממקום מסוים למקום אחר ואז מקדמת את האינדקסים בשתיים, דבר זה נותן שאם מכוונים אותה כמו שצריך ניתן להעתיק הרבה מידע וקוד פשוט בעזרת הפעלת הפקודה הזאת שוב ושוב. באופן ספציפי היא מעתיקה שתי בתים (גודל שנקרא גם מילה) מ DS:SI ל ES:DI ואז מוסיפה ל SI ול DI את המספר 2. בתחילת המשחק DS מצביע לזירה ו ES אל האזור המשותף אז הפקודה מעתיקה מהזירה אל האזור המשותף.
Rep- הפקודה מריצה את הפקודה שאחריה CX פעמים, חשוב לציין שכל הרצה עולה סיבוב אחד במנוע. כלומר rep movsw עם cx=3 זה אותו דבר כמו הפקודה movsw שלוש פעמים ברצף חוץ מזה שזה תופס פחות מקום בזיכרון. דבר זה שימושי להעתקות ארוכות שבהם צריך להריץ את movsw עשרות פעמים. (חשוב לציין ש rep עובד רק עם פקודות מסוימות ולא עם כולם).
Movsb- אותו דבר כמו movsw רק עם בית אחד כל פעם במקום מילה כל פעם.אני ממליץ לך לקמפל ולהריץ את הקוד בדיבאגר (לדוגמא זה שיואב כתב שאפשר למצוא אותו פה בפורום ובעמודי מידע), ככה תוכל לראות מה הקוד עושה בכל שלב ומה רשום לא באוגרים בכל רגע.
עידן.
Idan Dorמשתתףהדוגמא הבאה היא שורד פשוט ובסיסי, בנוסף היא בכוונה לא יעילה. היא מבוססת על שורד בשם MAMALIGA (שלאחר שניצח לפני כמה שנים שחרר את קוד המקור עם הסבר פה בפורום).
base_jump_length = 0x0a00
jump_length = -(base_jump_length)
@Start:
add ax, @ZombieCodeAndJump – @Start
mov si, ax
push ax
mov ax, 0xa4a4
mov dx, 0xa4a4
int 0x86
mov cx, @End – @ZombieCodeAndJump
rep movswpop ax
push ds
push es
pop ds
pop es
mov di, ax
xor si, si
movsb@ZombieCodeAndJump:
movsw
movsw
movsw
movsw
movsw
movsw
movsw
add di,jump_length
movsw
db 0xE9
dw jump_length
movsw
xor si,si
movsb
@End:הקוד עושה את הדברים הבאים:
כותב בעזרת int86 את הפקודה movsb לזיכרון המשותף (סגמנט ES) הרבה פעמים (256).
לאחר ההפצצה הזאתי הוא מעתיק קוד קפיצה (בעזרת rep movsw) לאחר מה שהוא כתב קודם.
מחליף את הסגמנטים ES ו DS כך שעכשיו movsw ו movsb מעתיקים מהסגמנט המשותף אל הזירה ולא להפך.
מתחיל להעתיק את הקוד בעזרת movsb.דבר זה גורם לכך שהוא כל הזמן מעתיק קוד מ ES מריץ אותו ואז מעתיק עוד קוד עד שהוא מגיע לקוד הקפיצה שעביר אותו למקום אחד ואז הוא עושה אותו דבר שמה.
כפי שציינתי קודם, מה שהשורד עושה הוא איננו הפצצה יעילה אבל הוא מהווה דוגמא פשוטה יחסית לשורד טוב.
בנוסף, לא חובה להשתמש ב ES וב movsw כדי לגרום לשורד לזוז וניתן ליצור בקלות שורד שפשוט מעתיק את עצמו ממקום למקום אבל שורד זה יהיה מאוד פגיע בניגוד לדוגמא שבה הקוד מוגן מכיוון שהוא מאוחסן ב ES.עידן.
Idan Dorמשתתףהדוגמא של עדי איננה מגינה עליך מלפגוע באצמך, הדבר היחידי שהדוגמא של עדי בודקת זה האם המיקום הבא להפצצה הוא בדיוק המיקום ההתחלתי שלך (AX). שים לב ש AX לא משתנה לבד בקוד (אלה אם אתה משנה אותו) ומצביע רק על המיקום ההתחלתי שלך.
מה שזה אומר שאם אתה מפציץ באלכסון הקוד של עדי לא יגן עליך אלה יגן רק על הבית הראשון של הקוד שלך.אתה יכול להזיז את השחקן שלך לכל מקום שאתה רוצה (לדוגמא עם jmp bx) אבל אתה צריך לדאוג שיהיה שם קוד להריץ. המנוע (ומהמחשב) תמיד מריץ את הפקודה שרשומה במיקום IP בזיכרון (הכתובת המלאה היא CS:IP אבל זה לא משנה כרגע) אם דאגת לשים שם קוד שעושה משהו אז אין בעיה והוא ירוץ לאחר שתקפוץ לשם, אם לא כתבת שם קוד אז המנוע יגרום לך להריץ את מה שרשום שם וכנראה תמות בגלל פקודה לא חוקית.
מרבית השורדים מזיזים את עצמם כל הזמן וכותבים את הקוד שלהם מחדש כל פעם.עידן.
Idan Dorמשתתףשלום כפיר,
חשוב לי לבהיר את מה שרשמתי בתשובתי לשאלתך הראשונה, כי שכחתי לציין משהו.
סדר ההרצה נקבע כל פעם שנטענים שורדים לזירה, כלומר, לאורך 200,000 הסיבובים בכל משחק הסדר נשאר זהה (הוא מתחיל רנדומלית, אבל הוא נשאר זהה לאורך כל משחק כך שאם אתה יודע שאתה לפני קבוצת כלשהית במשחק כלשהו זה ישאר כך כל המשחק ההוא. דבר זה חשוב לדעת לניסיונות של סנכרון עם הזומבים).
הסדר כפי שרשמתי מיקודם הוא רנדומלי בין הקבוצות ואלפבתי באותה הקבוצה.עידן.
Idan Dorמשתתףכפי שרשום פה:
https://github.com/codeguru-il/corewars8086/blob/master/src/main/java/il/co/codeguru/corewars8086/war/War.java
בקוד המקור של המנוע בפונקציה:
private short getLoadOffsetהמרחק נמדד בין סוף של אחד להתחלה של השורד הבא. כלומר, לא יהיה משום כיוון שלכם קוד של מישהו אחר במרחק מינימלי של 1024 בתים.
עידן, קבוצת SilentError.
Idan Dorמשתתףשלום כפיר,
1. לא בדיוק, הסדר בין הקבוצות (כולל הזומבים) הוא רנדומלי ובתוך הקבוצות הוא אלפבתי, כלומר zombiea לפני zombieb אבל הם לא בהכרח יהיו בסוף.
2. כן, לכן חשוב להרוג את הזומבים לפני הסוף (אם אתה משתלט עליהם).
3. אני משאר שאתה משתמש בדיבאגר שיש אליו לינק בהסברים? זה דיבאגר קצת ישן כבר שכתב קיריל והוא משתמש בדיאסמבלר בשם NASM שאתה צריך שיהיה במיקום יחסי כלשהו למנוע וזה מה שגורם לך לבעיות. במקום להשתמש בו אני ממליץ לך להשתמש בדיבאגר שהקבוצה שלי פירסמה לפני חצי שני פה בפורום שהוא אמור להיות יותר נוח לשימוש והוא יותר מעודכן.
אם יש לך עוד שאלות, אשמח לענות.
עידן מקבוצת SilentError.
נ.ב. עודד, לא כדי שתשנה את הלינק לדיבאגר מעומדי ההסבר לדיבאגר שלנו? (או שתוסיף אליו שם לינק?)
Idan Dorמשתתףשלום עידו, בתור אחד שיש לו סקריפט כזה (שכנראה נשחרר מתישהו אם יהיה לנו כח לזה) אתה צריך לעשות את השלבים הבאים:
1)השגת אסמבלר (אני משתמש ב FASM) שעובד בהרצה שקטה(כאילו הרצה עם subprocess).
2)הכנת תוכנה שמקמפלת ומעבירה את הקבצים מהתקיית קודים לתקיית survivors.
3)תסתכל בקוד של הדיבאגר שיואב פירסם, אני לא זוכר בדיוק איך אבל אפשר להריץ אותו בהרצה שקטה.
4)הכנת קטע קוד שמשנה את המשתנים שאתה רוצה ורק אותם לקודים מסוימים.
5)הכנת קטע קוד שיאפשר לך לקרוא/להעתיק/לשמור מידע מקובץ ה CSV של תוצאות המנוע.
6)אני ממליץ לשמור את התוצאות ופשוט להיכנס אחרי זה לאקסל, למיין את המידע לפי משהו מסויים, ולבחור את המשתנים שאתה רוצה ידנית בהתאם לתוצאה הרצוייה.שים לב:
תשים בתיקיית survivors שורדים שנגדם אתה רוצה שמשתנים יעבדו הכי טוב, נגד כל שורד כנראה שיהיה משהו אחר…אני ממליץ לך שכל משתנה שאתה יכול לחשב/להחליט אסטרתגית תעשה את זה. את מרבית הקבועים ניתן לדעת מה הם דרושים להיות.
מכווה שזה עוזר ואם יש לך עוד שאלות אז תשאל.
עידן מ SilentErrorIdan Dorמשתתףמנוע המשחק אינו תומך בקידומת של סגמנטים.
אתה צריך לעשות משהו כמו:
push es
pop ds
mov word [0x22], siIdan Dorמשתתףאיך אפשר לשלוט בערך המוכנס למחסנית? אי אפשר, אלה אם כן אתה מוכן לעשות את ה CALLFAR ממקום ספציפי.
האם אני….? כן^^
שאלה נוספת….? לא כתיבה במחסנית זה תמיד קטן אין דרך להפוך את המחסנית.Idan Dorמשתתףלגבי הרצה שקטה והרצה רק עם השורד שלך – אני ויואב אחרי קודגורו 9 הכנו לעצמנו דיבאגר חדש שבין השאר יש בו את שתי הדברים האלו. אנחנו מתכננים לשחרר אותו אחרי שנשתתף התחרות הקרובה בנוסף לכלים נוספים שהכנו בשנה האחרונה. אין את האופציות האלו במנוע ואם אתה רוצה אותם אתה תאלץ לכתוב אותם בעזרת הקוד הפתוח של המנוע שנמצא פה:
https://github.com/codeguru-il/corewars8086בהצלחה.
-
מאתתגובות