OSDev.org

The Place to Start for Operating System Developers
It is currently Thu Mar 28, 2024 1:48 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 3 posts ] 
Author Message
 Post subject: Global C data incorrectly initialized
PostPosted: Mon May 01, 2017 8:27 pm 
Offline

Joined: Tue Apr 04, 2017 2:37 pm
Posts: 19
I'm sure I'm making a rookie mistake; but, I just don't see it. My global C variables appear to have the wrong values in them after I enter protected mode.

At the moment I have a very simple boot loader that follows the example of x86 bare metal (https://github.com/cirosantilli/x86-bare-metal-examples) and OSDev's Bare Bones to load the rest of the code, enter protected mode, and call the C function that is the kernel entry point. I also have a few functions that can write using VGA text mode.

The C file with the kernel entry point has two initialized global variables. I enter the kernel (function dd_test) and immediately test the global variables. They have the wrong values. More interestingly, the values that are in the variables are part of a string embedded at the end of the MBR. Specifically, even though the global variable is placed at memory address 0x9818, the value printed is the data loaded at address 0x7ce4. (I doubt the problem is the VGA code because I check their values before running the VGA code.)

I've used hexdump to examine the boot image, and the global variables have the expected addresses. (Printing &d1 displays 0x9818, which is what I would expect given that the d1's initial value appears at location 0x1c18 in the hexdump and 0x1c18 + 0x7c00 = 0x9818)

My guess is that I'm overlooking some subtlety of either linking or switching to protected mode. Any ideas?

Code:
// kernel entry point
unsigned d1 = 0x4b4b4b4b;
unsigned d2 = 0x4c4c4c4c;

void dd_test() {

  int correct_value;
  if (d1 == 0x4b4b4b4b) {
    correct_value = 1;
  } else {
    correct_value = 0;
  }
 
  vga_text_section_t head, body;
  vgat_initialize_head_body(&head, &body, 7);

  if (correct_value == 1) {
    vgat_write_string(&head, "\nCorrect\n");
  } else {
    vgat_write_string(&head, "\nIncorrect \n");
    vgat_write_unsigned_hex(&head, d1, " <= d1 value; ");
    vgat_write_unsigned_hex(&head, (unsigned) &d1, " <= &d1\n");
    vgat_write_unsigned_hex(&head, d2, " <= d2 value; ");
    vgat_write_unsigned_hex(&head, (unsigned) &d2, " <= &d2;\n");
  }


Output from running OS:
Code:
Incorrect
0x20657265 <= d1 value; 0x9818 <= &d1
0x7473756a <= d2 value; 0x981c <= &d2


Relevant portions of hexdump of image

Code:
000000b0  7c 00 00 66 b8 10 00 8e  d8 8e c0 8e e0 8e e8 8e  ||..f............|
000000c0  d0 bd 00 70 00 00 89 ec  e9 33 01 00 00 45 6e 64  |...p.....3...End|
000000d0  20 6f 66 20 4d 42 52 2e  20 20 4d 6f 72 65 20 74  | of MBR.  More t|
000000e0  65 78 74 20 68 65 72 65  20 6a 75 73 74 20 74 6f  |ext here just to|
000000f0  20 74 61 6b 65 20 75 70  20 72 6f 6f 6d 2e 00 66  | take up room..f|
00000100  90 66 90 66 90 66 90 66  90 66 90 66 90 66 90 66  |.f.f.f.f.f.f.f.f|

...

00001b10  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00001c00  47 47 47 47 70 70 70 70  53 52 51 54 57 57 57 57  |GGGGppppSRQTWWWW|
00001c10  7a 7a 00 00 79 79 79 79  4b 4b 4b 4b 4c 4c 4c 4c  |zz..yyyyKKKKLLLL|
00001c20  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*


The linker script

Code:
SECTIONS
{
  . = 0x7c00; __start = .;

  /* First place the code (aka "text") in the image */
  .text :
  {
    *(.boot) // the MBR in boot.S
    . = 0x1FE;
     SHORT(0xAA55)

     /* The code in the ".boot" section (the first 512 bytes) is
        responsible for issuing the BIOS calls to load the next
        sections of code.  If you look in boot.S, you will see that
        the code for this second stage of booting is placed in
        ".section .stage2".  The line below places this startup code
        immediately following the boot sector.  "stage2" contains code
        that moves the processor from "real" mode to "protected" mode,
        then calls the function that represents the entry point of the
        OS. */
    *(.stage2)

    /* All other code (i.e., code that is not part of the boot loader)
       is placed in ".section .text".  The line below instructs the
       linker to place this remaining code next in the image. */
    *(.text)
  }


  /* Read-only data.  When generating assembly code, gcc places
     hard-coded strings (among other things) in .section .rodata */
  .rodata ALIGN(1024) :
  {
    LONG(0x35343332);  /* Mark the beginning of rodata. */
    *(.rodata*)
    LONG(0x32444E45);  /* Mark the end of the disk rodata. */
  }

  /* Read-write data.  When generating assembly code, gcc places
  global and static data in .section .data. */
  .data : ALIGN(1024)
  {
    LONG(0x47474747) // mark the beginning of .data
    *(.data)
  }


   // Not used yet.  Just filled with some data so I can see how the linker works.
  .data2 :  ALIGN(1024)
  {
    *(.data2)
  }

  /* Calculate the total number of sectors used by the code and data.
      Normally, the "." gives the value of the linker's internal
      pointer relative to the current section.  Surrounding the
      calculation with ABSOLUTE assures that the values used are
      relative to the entire image.  This value is used in boot.S to
      specify the number of sectors that must be loaded
  */
   __stage2_nsectors = ABSOLUTE((. - __start) / 512);

   /* Ensure that the generated image is a multiple of 512 bytes
   long. (Some machines and VMs freak out if the boot image is not a
   multiple of 512 bytes. */
   __end = .;
   __end_align_4k = ALIGN(4k);


  // Make sure image is a multiple of 512 bytes   

.data3 : ALIGN(1024)
  {
    . = 512 -4;  /* Make sure that the disk image is a multiple of 512 bytes.  */
    LONG(0x444E4500);  /* Mark the end of the disk image. */
  }   


Top
 Profile  
 
 Post subject: Re: Global C data incorrectly initialized
PostPosted: Tue May 02, 2017 6:18 am 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5100
kurmasz wrote:
Any ideas?

Now would be a great time to learn how to use the debugger in your favorite virtual machine. For example, you might try single-stepping your code to find the instruction that loads the strange values, or maybe set some breakpoints and dump the register contents to find anything out of the ordinary.


Top
 Profile  
 
 Post subject: Re: Global C data incorrectly initialized
PostPosted: Tue May 02, 2017 7:01 am 
Offline

Joined: Tue Apr 04, 2017 2:37 pm
Posts: 19
Doh! It was a long-forgotten piece of debugging code in my boot.S that was making changes. :oops:

Thanks for pointing me at the VM's debugger.

When I had toddlers, I use to say "Any sentence that begins with 'He can't possibly ...'" is wrong. I'm learning that the same principle applies to writing an OS.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 3 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: No registered users and 71 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group