最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

assembly - Performing multiplication of 32-bit numbers in 16-bit real mode in order to traverse FAT table - Stack Overflow

programmeradmin3浏览0评论

I am writing a simple bootloader (and, hopefully soon, an operating system). I have been making progress, but this part is stumping me a bit.

I am writing this operating system and bootloader into a disk image, which consists of:

  1. An MBR boot sector and a first stage bootloader
  2. A 32kb reserved area for the second stage bootloader
  3. A FAT32 partition that holds the operating system, and kernel.bin

My goal is to load kernel.bin into memory and jump to it, and in order to do this I must traverse the FAT tables.

A lot of logic involved in reading the FAT32 partition requires 32-bit values (like many BPB values)

Since I am essentially locked in real mode for now, I'm not sure how to handle these 32-bit numbers when performing calculations like multiplication. I know I can use 32-bit registers using the operand size prefix and/or address size prefix, but I can't really use arithmetic operations on them in a meaningful way.

Example

Here is a section of assembly that stores important values from the BPB:

BPB_info:

    ; BPB info from the FAT32 boot sector
    BPB_NumFATs: db 0 ; Number of FATs (1 byte)
    BPB_FATSz32: dd 0 ; Size of each FAT in sectors (4 bytes)
    BPB_RootClus: dd 0 ; First cluster of the root directory (4 bytes)
    BPB_SecPerClus: db 0 ; Sectors per cluster (1 byte)
    BPB_RsvdSecCnt: dw 0 ; Reserved sectors count (2 bytes)

    ; Calculated values used in the bootloader
    FAT_root_dir_start: dq 0 ; Start of the root directory in sectors (calculated)
    FAT_lba: dq 0 ; Logical block address of the FAT tables (calculated)

In order to calculate FAT_root_dir_start, I must use the following formula:

BPB_RsvdSecCnt + ((BPB_RootClus - 2) * BPB_SecPerClus)

But since BPB_RootClus is a doubleword (32 bits) I'm not sure how to carry out this operation.

Any advice would be appreciated! Am I on the right track? Should I approach this completely differently? Maybe switch to protected mode? I'm not sure.

I am writing a simple bootloader (and, hopefully soon, an operating system). I have been making progress, but this part is stumping me a bit.

I am writing this operating system and bootloader into a disk image, which consists of:

  1. An MBR boot sector and a first stage bootloader
  2. A 32kb reserved area for the second stage bootloader
  3. A FAT32 partition that holds the operating system, and kernel.bin

My goal is to load kernel.bin into memory and jump to it, and in order to do this I must traverse the FAT tables.

A lot of logic involved in reading the FAT32 partition requires 32-bit values (like many BPB values)

Since I am essentially locked in real mode for now, I'm not sure how to handle these 32-bit numbers when performing calculations like multiplication. I know I can use 32-bit registers using the operand size prefix and/or address size prefix, but I can't really use arithmetic operations on them in a meaningful way.

Example

Here is a section of assembly that stores important values from the BPB:

BPB_info:

    ; BPB info from the FAT32 boot sector
    BPB_NumFATs: db 0 ; Number of FATs (1 byte)
    BPB_FATSz32: dd 0 ; Size of each FAT in sectors (4 bytes)
    BPB_RootClus: dd 0 ; First cluster of the root directory (4 bytes)
    BPB_SecPerClus: db 0 ; Sectors per cluster (1 byte)
    BPB_RsvdSecCnt: dw 0 ; Reserved sectors count (2 bytes)

    ; Calculated values used in the bootloader
    FAT_root_dir_start: dq 0 ; Start of the root directory in sectors (calculated)
    FAT_lba: dq 0 ; Logical block address of the FAT tables (calculated)

In order to calculate FAT_root_dir_start, I must use the following formula:

BPB_RsvdSecCnt + ((BPB_RootClus - 2) * BPB_SecPerClus)

But since BPB_RootClus is a doubleword (32 bits) I'm not sure how to carry out this operation.

Any advice would be appreciated! Am I on the right track? Should I approach this completely differently? Maybe switch to protected mode? I'm not sure.

Share Improve this question edited Mar 30 at 18:20 Sep Roland 39.9k10 gold badges48 silver badges88 bronze badges asked Mar 30 at 5:07 Ryan GrubeRyan Grube 232 bronze badges 4
  • See this related question. – user207421 Commented Mar 30 at 5:43
  • From what I am reading, sectors per cluster is guaranteed to be a power of two, so in principle you could use a shift rather than a multiply. It does still need to be 32 bits wide, though. – Nate Eldredge Commented Mar 31 at 2:41
  • "I know I can use 32-bit registers using the operand size prefix and/or address size prefix, but I can't really use arithmetic operations on them in a meaningful way." I think this is where you are mistaken. When you use an operand size prefix on an arithmetic instruction, not only do you get to use 32-bit registers, you actually get to do full 32-bit-wide arithmetic, just like the default behavior in protected mode. add eax, ebx (66 01 D8) does a full 32-bit add, and mul/imul with a prefix do full 32-bit multiplies. – Nate Eldredge Commented Mar 31 at 2:45
  • @NateEldredge - Yes, you are exactly right, that is where I was confused. Thank you! – Ryan Grube Commented Mar 31 at 4:14
Add a comment  | 

1 Answer 1

Reset to default 3

If you want to stick to a strict x86 instruction set then you are looking at a typical long multiplication problem (Multiplying 64-bit number by a 32-bit number in 8086 asm for an explanation as pointed out by @user207421). In assembly:

mov cx, [BPB_RootClus + 2]
mov ax, [BPB_RootClus]
sub ax, 2  ; cx:ax = BPB_RootClus - 2 = X; cx = Xh, ax=Xl
sbb cx, 0
mov bl, [BPB_SecPerClus] ; bx = y
mov bh, 0
mul bx  ; dx:ax = Xl * y
xchg ax, bx ; dx:bx = Xl * y, ax = y
mov bp, dx ; bp:bx = Xl * y
mul cx ; dx:ax = Xh * y
add ax, bp 
; adc dx, 0 - that'd be a carry-over but we'll assume that mutiplication result can fit into 32 bit

; now X * y is in ax:bx pair, add BPB_RsvdSecCnt
add bx, [BPB_RsvdSecCnt]
adc ax, 0

However if you are OK with using 80386 32-bit instructions (using OPERAND size override, not an address size override though) then I don't really see any problem with simply using 32 bit arithmetics:

bits 16
cpu 386
...
mov eax, [BPB_RootClus]
sub eax, 2
movzx edx, byte [BPB_SecPerClus]
mul edx
movzx edx, word [BPB_RsvdSecCnt]
add eax, edx

That ought to compile and work just fine.

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论