2

My CPU is little endian, which documentation has told me conforms to the byte-order of the FAT specification. Why then, am I getting a valid address for the BS_jmpBoot, bytes 0-3 of first sector, but not getting a valid number for BPB_BytesPerSec, bytes 11-12 of the first sector.

116         int fd = open (diskpath, O_RDONLY, S_IROTH);
117 
118         read (fd, BS_jmpBoot, 3);
119         printf("BS_jmpBoot = 0x%02x%02x%02x\n", BS_jmpBoot[0], S_jmpBoot[1], S_jmpBoot[2]);
120 
121         read (fd, OEMName, 8);
122         OEMName[8] = '\0';
123         printf("OEMName = %s\n", OEMName);
124 
125         read (fd, BPB_BytesPerSec, 2);
126         printf("BPB_BytesPerSec = 0x%02x%02x\n",BPB_BytesPerSec[0], BPB_BytesPerSec[1]);

Yields

BS_jmpBoot = 0xeb5890                  //valid address, while 0x9058eb would not be
OEMName = MSDOS5.0
BPB_BytesPerSec = 0x0002               //Should be 0x0200

I would like figure out why BS_jmpBoot and OEMName print valid but BPB_BytesPerSec does not. If anyone could enlighten me I would be greatly appreciative.

Thanks

EDIT: Thanks for the help everyone, it was my types that were making everything go awry. I got it to work by writing the bytes to an unsigned short, as uesp suggested(kinda), but I would still like to know why this didn't work:

            unsigned char BPB_BytesPerSec[2];
...
125         read (fd, BPB_BytesPerSec, 2);
126         printf("BPB_BytesPerSec = 0x%04x\n", *BPB_BytesPerSec);

yielded BPB_BytesPerSec = 0x0000

I would like to use char arrays to allocate the space because I want to be sure of the space I'm writing to on any machine; or should I not?

Thanks again!

Kdawg
  • 167
  • 11
  • `read (fd, BS_jmpBoot, 3);` -->>`read (fd, BS_jmpBoot, 4);` BTW, **WHAT** is `BS_jmpBoot` ? – wildplasser Nov 26 '14 at 21:15
  • @wildplasser - in ye ancient floppy disks, the boot sector could contain executable code - for DOS that would be in 16-bit 8086 machine code. That was run by literally jumping into the start of the boot sector once it was in RAM. However, there's reserved fields at the start of the boot sector describing the disk format - up to around 64 bytes out of 512 depending on DOS version - so the first three bytes were reserved for a jump instruction to the real executable code. –  Nov 26 '14 at 21:45
  • I know that (been there, done that) I was referring to the absence of a definition for `BS_jmpBoot` But in fact the (IMHO correct method is to read the full 512 byte sector in one sweep, and then pick the correct pieces. – wildplasser Nov 26 '14 at 21:57
  • @wildplasser - I'm going to guess this is for floppy image files by now, so one option is to use memory-mapped files if you don't mind platform-specific code. Personally, when reading binary files, I have a library that caches a few blocks in the background and provides a bunch of `peek_` methods - mainly to keep the file reading, endian and similar issues from cluttering up the parsing. –  Nov 26 '14 at 22:13

2 Answers2

3

You are reading BPB_BytesPerSec incorrectly. The structure of the Bpb is (from here):

BYTE  BS_jmpBoot[3];
BYTE  BS_OEMName[8];
WORD  BPB_BytesPerSec;
...

The first two fields are bytes so their endianness is irrelevant (I think). BPB_BytesPerSec is a WORD (assuming 2 bytes) so you should define/read it like:

WORD BPB_BytesPerSec;            //Assuming WORD is defined on your system
read (fd, &BPB_BytesPerSec, 2);
printf("BPB_BytesPerSec = 0x%04x\n", BPB_BytesPerSec); 

Since when you read the bytes directly you get 00 02, which is 0x0200 in little endian, you should correctly read BPB_BytesPerSec like this.

uesp
  • 6,194
  • 20
  • 15
2

First of all, this line:

printf("BPB_BytesPerSec = 0x%02x%02x\n",BPB_BytesPerSec[0], BPB_BytesPerSec[1]);

is printing the value out in big endian format. If it prints 0x0002 here, the actual value would be 0x0200 in little endian.

As for the BS_jmpBoot value, according to this site:

The first three bytes EB 3C and 90 disassemble to JMP SHORT 3C NOP. (The 3C value may be different.) The reason for this is to jump over the disk format information (the BPB and EBPB). Since the first sector of the disk is loaded into ram at location 0x0000:0x7c00 and executed, without this jump, the processor would attempt to execute data that isn't code.

In other words, the first 3 bytes are opcodes which are three separate bytes, not one little endian value.

JS1
  • 4,745
  • 1
  • 14
  • 19
  • The bytes for BS_jmpBoot are correct - for DOS either "E9 XX XX" for a 16-bit jump or "EB XX 90" for a short jump followed by a NOP, either way jumping to the boot code. As uesp says, though, that field is a sequence of bytes (containing 16-bit x86 machine code) - endianness doesn't apply. Sticking an `0x` in front of the output doesn't mean the sequence of bytes is anything other than a sequence of bytes. The problem with bytes-per-sector is that he isn't converting from the component bytes back to a single value - that's when you worry about endian-ness. –  Nov 26 '14 at 21:34
  • I understand perfectly well what the problem is. I'm just trying to explain it in the simplest way. I probably didn't do a very good job explaining. – JS1 Nov 26 '14 at 21:43
  • I'm not trying to contradict, only suggesting possible tweaks. –  Nov 26 '14 at 21:46