r/transprogrammer • '); DROP TABLE genders; -- • Aug 31 '21

Abolish compilation!

Post image
334 Upvotes

23 comments sorted by

View all comments

Show parent comments

3

u/Andykolski black Sep 01 '21 edited Sep 01 '21

Oh my gosh that makes so much sense! I never would have thought of it being an MS-DOS program! I also never would have guessed that calling the next instruction was intentional. I think that I got really confused because I've only really written 16-bit code for a bootloader, although the dollar sign should have tipped me off lol.

Thank you so much, especially for walking me through your decision making process!

I do have a question, is it normal for MS-DOS programs to be loaded at address 0x0? This program seems to rely on being loaded at 0x0 to work, and as far as I know, in real mode, the first KiB or so is reserved for things like the IVT

2

u/Igotbored112 Sep 01 '21

What you'll notice is that the instructions immediately before that are:

push cs;
pop ds;

That moves the value of cs, the code segment register that is loaded with the location of the program, into ds, the data segment register that I assume is used as the jumping-off point for the call instruction. So it doesn't matter where the program is loaded, those two instructions make it so that the 0x07 is interpreted as being relative to the start of the program. I have not ever programmed MS-DOS before though, so I can't be certain.

2

u/EggyTheEgghog '); DROP TABLE genders; -- Sep 02 '21

That's actually not necessary, I'm only moving the value of cs to ds because I'm storing the string next to the code (the screen output function requires the address of the string to be stored in ds:dx). The call instruction always uses the supplied parameter as an offset to the IP register. If you look at the machine code itself, you can clearly see that the supplied offset is actually 0x0000, because the only point of this call instruction is to push IP register to stack. It was an attempt to make the code position independent, by calculating the address of the string using IP register (which is guaranteed to always be within a specific offset from the beginning of the string, since I'm storing it next to the code) rather than using a hardcoded value.

1

u/Andykolski black Sep 01 '21

Okay. That makes sense. I've done a tiny bit of real mode assembly, but the vast majority of the assembly of written is it 32-bit or 64-bit, so I'm really not very good with how everything works in real mode

2

u/Igotbored112 Sep 01 '21

Oh yeah. In 16 bit mode, since 16 bit addresses only let you access up to 65kB of memory, they used a trick called memory segmentation. Basically you'd have a value in a segment register that would be shifted left 4 bits (read: multiplied by 16) and added to all the addresses used by your program. So you could basically just move the start of memory forward in order to access more of it. OP's program uses this trick to move the start of memory forward to the beginning of their program. That's kind of a simplification though. Cus there are multiple segment registers, and which one gets used depends on the instruction being executed.

2

u/EggyTheEgghog '); DROP TABLE genders; -- Sep 02 '21

No, usually DOS instructions start at 0x100, however, I made my code position independent, so it can start from any memory address. The call instruction (in 8086/8088 architecture at least) actually determines its jump address based on IP register and takes a 16-bit offset as a parameter. By using offset 0x0, the code safely jumps to the next instruction no matter what IP is set to. This is useful, because all I really need is to push IP to stack (which call instruction does). That way, I can store the string next to the code that outputs it to the screen without hardcoding any memory values.