https://retrocomputing.stackexchange.com/questions/29565/does-this-8088-code-in-the-leisure-suit-larry-2-game-actually-do-anything Stack Exchange Network Stack Exchange network consists of 183 Q&A communities including Stack Overflow, the largest, most trusted online community for developers to learn, share their knowledge, and build their careers. Visit Stack Exchange [ ] Loading... 1. + Tour Start here for a quick overview of the site + Help Center Detailed answers to any questions you might have + Meta Discuss the workings and policies of this site + About Us Learn more about Stack Overflow the company, and our products 2. 3. current community + Retrocomputing help chat + Retrocomputing Meta your communities Sign up or log in to customize your list. more stack exchange communities company blog 4. 5. Log in 6. Sign up Retrocomputing 1. 1. Home 2. Questions 3. Tags 4. 5. Users 6. Companies 7. Unanswered 2. Teams Stack Overflow for Teams - Start collaborating and sharing organizational knowledge. [teams-illo-free-si] Create a free Team Why Teams? 3. Teams 4. Create free Team Teams Q&A for work Connect and share knowledge within a single location that is structured and easy to search. Learn more about Teams Does this 8088 code in the Leisure Suit Larry 2 game actually do anything? Ask Question Asked 3 days ago Modified today Viewed 40k times 53 In the Sierra On-Line game "Leisure Suit Larry 2" there's a part in the game where the main character (Larry) has to write a program in 8088 assembly language as part of his tribal initiation. Larry then jokes that he's written a multi-user operating system called "Eunuchs". Animated screenshot showing the scene from the game The code shown in the game is: INT 21 JB 0103 MOV AH,4D INT 21 CS: MOV [0BEA],AX JMP 02B2 JMP 1451 CS: TEST BYTE PTR [0C59],01 JZ 0150 CS: TEST BYTE PTR [0C59],02 JZ 014F IRET INT 21 JB 0103 TEST BYTE PTR [0C59],04 JZ 0169 CMP AH,01 JA 014F I haven't run this code as I presume it probably isn't complete, but does anyone know what it might do? * programming * assembly * gaming Share Improve this question Follow edited 2 days ago user3840170's user avatar user3840170 23k44 gold badges9191 silver badges149149 bronze badges asked Feb 24 at 23:17 Noel Whitemore's user avatar Noel WhitemoreNoel Whitemore 69311 gold badge33 silver badges1212 bronze badges New contributor Noel Whitemore is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct. 8 * 8 It seems to be nonsense. Some of the int 21h calls don't specify the call, and AH = 4D requests the result of an exec call which hasn't been made. There's a spurious IRET in the middle of it. The jump and branch destinations are meaningless without more context. The protagonist can't have written a "multiuser OS" in 20 lines using MS-DOS calls. It's the code equivalent of a panel with fake leds and gauges. - Weather Vane Feb 24 at 23:42 * 15 Most people here may already know this, but "Eunuchs" is a pun on UNIX, which is an actual multi-user operating system (but it never ran natively on an 8088). And UNIX was, itself, a pun - it was envisioned as a simpler version of MULTICS. - Jacob Krall Feb 25 at 1:40 * 9 @JacobKrall Unix was of course available for the 8088PC/XT. Even trice, first as V7 based Venix/86, then as System III based Xenix 3 Release 1 by SCO and last as System V based PX/ix by IBM (developed by Interactive Systems). All in the 1983/1984 time frame and each under genuine AT&T licence. - Raffzahn Feb 25 at 4:11 * 4 @JacobKrall memory protection is a good thing, not just for multi user, even on single user/single tasking like DOS. Still, it's just a nice add on, not necessary for anything. Also, Unix does not need multiple users either. - Raffzahn Feb 25 at 12:08 * 10 Being Leisure Suite Larry, I'm somewhat surprised it's not 80085 Assembly language! - Jon P 2 days ago | Show 3 more comments 3 Answers 3 Sorted by: Reset to default [Highest score (default) ] 47 It's most definitely not a program 'written' by a programmer, but rather a listing of some random program segment using the disassembly command of a debugger. Have you tried to find that code within the program? Let's See What We Got Hard to say anything definitive with only this (incomplete) section. A few details visible are: 01: INT 21 ; An unknown (*1) call to DOS, function code would have been set prior to this line 02: JB 0103 ; Jump to address 0103h if DOS returns NO error 03: MOV AH,4D ; Get return code from DOS (*1) 04: INT 21 05: CS: ; (*2) 06: MOV [OBEA],AX ; Save return information within the program code at offset 0BEAh 07: JMP 02B2 ; Continue at 02B2h 08: JMP 1451 ; Continue at 1451h (*3) 09: CS: ; (*4) 10: TEST BYTE PTR [0C59],01 ; Test the lowest bit of the byte at 0C59h within code 11: JZ 0150 ; Continue at 0150h if not set (*6) 12: CS: 13: TEST BYTE PTR [OC59],02 ; Test the second lowest bit 14: JZ 014F ; Continue at 014Fh if not set (*6) 15: IRET ; Return from Interrupt to terminate the program(*5,*6) 16: INT 21 ; Again a an unknown DOS call (*7) 17: JB 0103 ; Continue at 0103h if no error reported (*8) 18: TEST BYTE PTR [0C59],04 ; Test the third lowest bit 19: JZ 0169 ; Continue at 0169h if not set 20: CMP AH,01 ; check AH for 01h (*7) 21: JA 014F ; If AH was greater than 01h continue at 014Fh (*9) *1 - Since the second INT 21h (L:04), made when an error is returned, asks DOS for a program's return code, the previous DOS call (L:01) was most likely an EXEC call to run a different program as child process. Using this function also tells that the program was written/ compiled for MS-DOS 2.0 or later. *2 - A hint that the debugger used was most likely the one supplied with MS-DOS. *3 - Line 08 might be a target from a previous branch, one like the one on L:02. Such would be a typical compiler structure to continue from a branch to a destination more than 128 bytes away. *4 - An entry point, like *2, except here operation continues *5 - Using an IRET here is a strong indicator that the program may be a .COM program and this being used to terminate it. DOS prepares the memory of a COM program much like CP/M, including a way that a jump at address 0000h will terminate it. This is done by placing it's original termination interrupt INT 20h at the start of the PSP - which is at CS:0 for COM programs - and pushing a word of 0000h onto the stack. Now a simple RET NEAR can be used to terminate. This of course only works if CS doesn't get changed inbetween. A condition true for most simple programs, especially such converted from 8080 code. To still use that way of termination while possibly changing CS during program run it was common for COM programs to start by pushing CS and another word of 0000h onto the stack. Now a RETF could used, no matter what content CS had at the moment (and as long as all stack levels were cleaned up). EXE programs added a little issue as their initial CS is not pointing to the PSP. But DS is loaded in both types with the PSP address, so pushing DS instead of CS would make the code usable for both types of program. Since that 'trick' would leave a a single word on stack (the one provided by DOS to start with), it became common to use an IRET instead of a RET FAR, which does take that word as well off the stack. Not that it made a difference, but it felt better :)) *6 - It's extreme hard to do any guess without knowing the address that code is located. But having two jumps targeted only one byte apart means that either some (for x86) unusual program trick is used, or 014Fh containing a single byte instruction. Considering that an IRET/INT combination is rather unusual and that IRET is a single byte instruction, it could quite well be that it's address is 014Fh. But then again the previous JZ wont make much sense, as either way would lead to taking the IRET. *7 - Checking AH after DOS functions is rare, as the standard return code is contained in AL (AX). Get Return code (see L:03/04) in turn does use AH and AL different. AL contains the child return code, while AH contains the termination reason. Here 00h/01h are regular termination reasons, while 02h is a critical error abort. Checking for above 01h would make sense if the previous INT 21h was as well an EXEC call. *7 - Note this being he same target as used on line 02, which seems to be the default good exit. *8 - Note this being he same target as used on line 14 --------------------------------------------------------------------- Conclusions From Code The code snipplet is most likely part of an exec function that starts a child program and checks if the execution went well and continues afterwards. It might thus be some menu system/framework starting overlay modules for different tasks (game sections??). It seems to be written in some High level language. Also, it's most likely not from DOS or any OS level software, but user space, as it used INT 21h functions. Using the IRET termination hints to some really old code with DOS 1.x origin, or a compiler using that trick to save code size if here are multiple termination points. It must be an older one, as MS discouraged use of returning via PSP:0 and INT 20h in general with DOS 3 Taking into account that the target for 'good' execution (L:02/L:17) points to a very low address within this code, this could be an endless loop starting around the loading and executing a child process. Together with the fact that it checks flags within its own code segment after returning from the child process to decide how to continue, I could imagine this being a loader for a larger program, whose only job is to reload that program whenever it got normally terminated, unless some flags have been set by the child before termination. A program like this could be a simple solution to catch certain errors without adding lots of error checking code within the application. Any error detection would just exit the child, which then gets restarted from above code. Note: These are all wild guesses, not necessary true. There is no way to tell where it's originated, unless one finds exactly that code in some program. Now, What is It? Nothing. I'd say they just started up their debugger, loaded some program, dumped a random section of 21 lines and copied them into the game text. Could be from the game or any other program. Share Improve this answer Follow edited yesterday answered Feb 24 at 23:48 Raffzahn's user avatar RaffzahnRaffzahn 219k2222 gold badges618618 silver badges908908 bronze badges 3 * Comments have been moved to chat; please do not continue the discussion here. Before posting a comment below this one, please review the purposes of comments. Comments that do not request clarification or suggest improvements usually belong as an answer , on Retrocomputing Meta, or in Retrocomputing Chat. Comments continuing discussion may be removed. - Chenmunka yesterday * 13 @Chenmunka Moving these comments seems like a _very_bad move as they contained a lot of follow up information (Like Al Lowes own reply). Those actions seem to be quite random and not really targeting off topic comments. Might be better for all to keep a more hands off approach. - Raffzahn yesterday * 2 It's tricky on this site as commeting happens more than on other SE sites and usually does have lots of fascinating (if not always directly relevant) info - comment threads more than 20 comments long get flagged by the system automatically and standard practice is to move them. I try and review each one individually, I've chosen to leave some in the past while migrating others. I didn't see these and maybe would have left them, but the system does make moving them the easiest and default option. - Matt Lacey 12 hours ago Add a comment | 72 In a brief email conversation with Al Lowe (yes, the man himself!) he suggested that he probably used the COMMAND.COM file as the basis for this code as it would have been installed on every PC. Booting up a vanilla copy of MS-DOS(R) Version 3.30 and using the debug tool on the COMMAND.COM file shows the following disassembled code: -u 12d 160 1133:012D CD21 INT 21 1133:012F 72D2 JB 0103 1133:0131 B44D MOV AH,4D 1133:0133 CD21 INT 21 1133:0135 2E CS: 1133:0136 A3EA0B MOV [0BEA],AX 1133:0139 E97601 JMP 02B2 1133:013C 2E CS: 1133:013D F606590C01 TEST BYTE PTR [0C59],01 1133:0142 740C JZ 0150 1133:0144 2E CS: 1133:0145 F606590C02 TEST BYTE PTR [0C59],02 1133:014A 7403 JZ 014F 1133:014C E90213 JMP 1451 1133:014F CF IRET 1133:0150 2E CS: 1133:0151 F606590C04 TEST BYTE PTR [0C59],04 1133:0156 7411 JZ 0169 1133:0158 80FC01 CMP AH,01 1133:015B 72F2 JB 014F 1133:015D 80FC0C CMP AH,0C 1133:0160 77ED JA 014F Accepting some variation in the byte code due to differences between MS-DOS versions, I think for all practical purposes this is fairly close to what's seen in the game. Share Improve this answer Follow edited 15 hours ago user3840170's user avatar user3840170 23k44 gold badges9191 silver badges149149 bronze badges answered yesterday Noel Whitemore's user avatar Noel WhitemoreNoel Whitemore 69311 gold badge33 silver badges1212 bronze badges New contributor Noel Whitemore is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct. 5 * 6 It's even go as far and say it's exactly that code. Making a lot more sense with the JMP 1451 being located before the IRET (at 014Ch). So I'd say that line got misplaced (or on purpose moved) when the DEBUG output was copied into the program. Likewise all jump addresses are going to meaningful locations. Not being present in DOS 1 or 2 makes sense considering that for DOS 3 large parts were rewritten. Lovely. Task well solved. - Raffzahn 23 hours ago * 2 So it's DOS. Not Eunuchs. How disappointing. :-| - Noufal Ibrahim 18 hours ago * 1 As far as I can tell, this is partly code that collects the return code after launching an executable (well, obviously), followed by an initial fragment of the ISR for the Ctrl+C interrupt (0x23). - user3840170 15 hours ago * Why not pick your own answer as accepted? Seriously, you deserve it. - user3840170 11 hours ago * 1 @user3840170 I think the answer that I accepted is still the best one, in the sense that I wanted to know what the code did rather than where it was from. Your answer was very relevant also because I used the byte searches to confirm the origin. Thank you for all your edits, btw. - Noel Whitemore 11 hours ago Add a comment | 16 On its own, not much. As a whole, the code doesn't seem to make much sense, though some instruction sequences in it do look realistic. Judging by the form of each instruction, the code was almost certainly obtained by disassembling some binary using MS-DOS's bundled debugger DEBUG. Almost all the syntax choices are consistent with the style used by that program: * segment-override prefixes are written on a separate line, as if they were stand-alone instructions * everything is written in capital letters * hexadecimal constants are written in full width (with leading zeroes) and without any numeric base suffixes * all memory locations are denoted with bare addresses and not symbolic references * memory operand size specifiers like BYTE PTR are only used when their lack would result in ambiguity * the branch instruction after a syscall is written with the mnemonic JB (jump if below), where manually-written code would more often use the mnemonic JC (jump if carry set) for the same instruction * no spaces after commas separating operands * the number of spaces between opcode mnemonics and operands (as stored in game files; this may be hard to measure when the game displays the code in a proportional font) matches DEBUG disassembly output exactly Not all of these are strong indicators, but their lack would have been a rather telling counter-indicator that the code came from some other source or was edited; but few kinds of edits would have been justifiable anyway, given that the code is basically used as mere filler text; maybe omitting a few insufficiently impressive-looking instructions, maybe removing excessive spaces to make text fit, maybe shuffling instructions around to make it not look like a blatant rip-off. But probably not code style adjustments. As for what it does, this is what I can tell from reading it: * At the beginning there is an MS-DOS syscall instruction, INT 21; we don't know which syscall it was meant to invoke, but judging by the following code, it was likely the "exec" syscall. It is followed by a test of the carry flag (which is how the DOS kernel signals errors), and then immediately by an invocation of the "wait"^0 syscall, the return value from which is stored in memory. This fragment looks rather realistic, if incomplete. * After that, there are two unconditional jump instructions, one after the other. [S:These may extend the range of conditional branch instructions elsewhere (on the 8086, conditional branches are normally limited to a 256-byte range), or maybe some shown here. Or they may be a dispatch table, though these usually do not appear after straight-line code.:S] Without the full code, I cannot tell. (Later: they turned out not to be next to each other in the original code.) * Further down, a single memory location has it bits checked, one after the other, with a conditional branch after each test. In the middle of it, there is an IRET instruction and a repetition of code from before; these look especially out of place, as if the code were altered. The subsequent bit test is missing a segment-override prefix that was present in previous ones; a sign that some opcodes from the original code were probably skipped. Other than that, this fragment also looks pretty typical. * And finally, there is a check whether the AH register is larger than 1, and a corresponding branch instruction. The code ends before any point where the result of that check could be used. [S:I can't help but wonder if this piece was meant to go after the "wait" syscall mentioned earlier.:S] (Later: It was not. But some code was skipped also here, which altered the meaning of the comparison.) All in all, I would guess that the code is a disassembly of a real binary [S:(or perhaps taken from two different binaries):S], which was then altered slightly and maybe had instructions shuffled in order to disguise the code's origin, and thus avoid a copyright-infringement lawsuit. [S:Or maybe it was obtained by launching DEBUG without loading any binary and then immediately disassembling, in which case it is a disassembly of whatever uninitialized contents the memory had at that time, which just so happened to be believably-looking code.:S] (My first hunch was correct, per the asker's own answer: it is a mangled opcode sequence from two different subroutines in COMMAND.COM that just happened to be placed near each other.) Unfortunately, the binary encoding corresponding to the jump/branch instructions will depend on the address from which they run (while MOV [0BEA],AX even has an ambiguous encoding, which may be either A3 EA 0B or 89 06 EA 0B; but it probably was the former), so recovering the binary opcodes from this assembly is not exactly trivial. [S:This means it will be pretty hard to identify the original binary code just from that listing.:S] If you want to hunt for the executable yourself, the longest instruction with an unambiguous encoding is (CS:) TEST BYTE PTR [0C59], xx which corresponds to the byte sequence (2E) F6 06 59 0C xx, and the first six lines of the listing probably correspond to a byte sequence matching CD 21 72 ?? B4 4D CD 21 2E A3 EA 0B. I was unable to find any binary with this code myself, but I did not look all that hard. (Maybe I would have, had the asker not beat me to it; this is what I get for rushing an answer against the FGITW. In hindsight, it would have been relatively easy to find even without the hint. But well done nevertheless.) --------------------------------------------------------------------- ^0 RBIL does not use this name, but MS-DOS did. It was one of many "Eunuchs" inspirations in MS-DOS 2. Share Improve this answer Follow edited 6 hours ago answered Feb 25 at 14:24 user3840170's user avatar user3840170user3840170 23k44 gold badges9191 silver badges149149 bronze badges 4 * Thank you for your answer and suggestions for byte searches. The closest match I could find for your CD 21 72 ?? B4 4D CD 21 2E A3 EA 0B byte string was 5F 5E 72 04 B4 4D CD 21 E9 C6 E7 00 which was in the install.exe file. This is in a segment of code that shortly after has copyright information for the "MS Run-Time Library". - Noel Whitemore Feb 25 at 14:52 * 1 @NoelWhitemore That's not even close, actually. B4 4D CD 21 is just MOV AH,4D / INT 21, which is almost bound to appear somewhere if a DOS program spawns subprocesses at all, but it isn't particularly specific. - user3840170 Feb 25 at 15:21 * @user3840170 I agree it's not close, but that's the closest match I've found in either of the executable files to part of your string. The other strings I couldn't match at all. - Noel Whitemore Feb 25 at 15:38 * 5 @user3840170 I heard back from Al. He thinks it might be from the COMMAND.COM file shipped with MS-DOS. I found a match for CD 21 72 D2 B4 4D CD 21 2E A3 early on in a random COMMAND.COM file from MS-DOS 3 I just downloaded off of archive.org so that looks promising. - Noel Whitemore yesterday Add a comment | You must log in to answer this question. Not the answer you're looking for? Browse other questions tagged * programming * assembly * gaming . * The Overflow Blog * How to convince your CEO it's worth paying down tech debt * Optimizing both hardware and software for GenAI sponsored post * Featured on Meta * Upcoming privacy updates: removal of the Activity data section and Google... * Changing how community leadership works on Stack Exchange: a proposal and... Linked 13 Difference between INT 0x20 and INT 0x21 (0x4C)? Related 11 How does JSR actually work on the 65c816 CPU for the SNES (Super Nintendo)? 9 Why does this 6502 code push a function address onto the stack before calling? 15 Why does this ZX Spectrum machine code "Hello World" routine not produce the expected result? 31 Does the video game Control (2019) depict a real computer system? What is it? 17 Does this 1978 code for a 6800 really clear ALL of memory? Hot Network Questions * Why can a isolated spherical conductor act as a capacitor? * Filtering CSV file * What happens if a slow train hits you? * Does the fingernail test for detecting two-way mirrors really work? * Function templates for serializing/deserializing POD types * Remove lines from a csv file based on column value * /sdcard/WhatsApp vs /sdcard/Android/media/com.whatsapp/WhatsApp * Tautologies in classical logic * Why doesn't this Technic bar fit? * How can psychic truffles keep humans from eating them? * Why are quantum effects of the apparatus ignored in quantum experiments? * A word for a man of few, but well thought-out, words * Can you use ha twice in a sentence? * How to split two answers from quadratic formula with arrows * Which European countries have laws that closely resemble the Russian law against discrediting the armed forces? * German pronunciation of English words * Why is net favorability for Israel so high in Nigeria even after the Gaza incursions? * How to color a selected set of variables in a ListPlot * How do we know that common rearrangement proofs of the Pythagorean theorem work for any right triangle? * Very basic question - cannot usepackage{chemformula} * getting into mathematical biology with a biology background * Need to re adjust the rear brakes when changing back wheel normal? * How does pitch bending work on keyboard percussion * Can I force a student to go back home? more hot questions Question feed Subscribe to RSS Question feed To subscribe to this RSS feed, copy and paste this URL into your RSS reader. [https://retrocomputi] * Retrocomputing * Tour * Help * Chat * Contact * Feedback Company * Stack Overflow * Teams * Advertising * Collectives * Talent * About * Press * Legal * Privacy Policy * Terms of Service * Cookie Settings * Cookie Policy Stack Exchange Network * Technology * Culture & recreation * Life & arts * Science * Professional * Business * API * Data * Blog * Facebook * Twitter * LinkedIn * Instagram Site design / logo (c) 2024 Stack Exchange Inc; user contributions licensed under CC BY-SA. rev 2024.2.28.5483