Page 1 of 1

Error: Trying to execute code outside RAM

Posted: Sun Feb 12, 2017 2:59 am
by MuchLearning
I've written a very simple kernel based in part on the Bare Bones tutorial. My working directory looks like

Code: Select all

boot.s   link.ld   kernel.c   terminal.h   terminal.c   Makefile
I am able to boot and run everything as expected until I include a static variable in either kernel.c or terminal.c, which causes the 'Trying to execute code outside RAM' error. My initial guess was that that static variable was messing up / overwriting the EIP somehow but I'm not sure how that would be possible. If I understand correctly static variables should get put on .bss which shouldn't mess with eip in any way at all.

**Edit**
I oversimplified things yesterday trying to reduce the problem down to a forum post friendly format. I failed to notice that including "terminal.h" and attempting to call a function from it is required to reproduce the error. The nature of the function called does not look to effect the error. Currently terminal.h declares a single function and terminal.c consists of two lines, one including terminal.h and an empty function definition for the function declared in terminal.h.

A static variable declared in either terminal.c or kernel.c causes the error to occur.

Code: Select all

//terminal.h
#ifndef TERM_HEADER
#define TERM_HEADER
void some_function_from_terminal_h();
#endif

Code: Select all

//terminal.c
#include "terminal.h"
void some_function_from_terminal_h(){}
My next guess was that a compile flag might be causing some weird behavior but after looking everything up I'm not so sure.
**Double Edit - I've also tried using a cross compiler but the issue is not resolved.**
Compiling with

Code: Select all

gcc -m32 -nostdlib -nostdinc -fno-builtin -fno-stack-protector \
           -nostartfiles -nodefaultlibs -c
and

Code: Select all

as --32
****

Anything to help me understand what is going on is greatly appreciated.

crash dump

Code: Select all

qemu: fatal: Trying to execute code outside RAM or ROM at 0xc36620e6
EAX=2badb002 EBX=00010000 ECX=00000000 EDX=00000000
ESI=00000000 EDI=00000000 EBP=20b0c366 ESP=fffffff0
EIP=c36620e6 EFL=00200086 [--S--P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
CS =0010 00000000 ffffffff 00cf9a00 DPL=0 CS32 [-R-]
SS =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
DS =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
FS =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
GS =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT=     00100380 00000020
IDT=     00000000 00000000
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000
DR6=ffff0ff0 DR7=00000400
CCS=00000008 CCD=fffffff0 CCO=SUBL
EFER=0000000000000000
FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001f80
FPR0=0000000000000000 0000 FPR1=0000000000000000 0000
FPR2=0000000000000000 0000 FPR3=0000000000000000 0000
FPR4=0000000000000000 0000 FPR5=0000000000000000 0000
FPR6=0000000000000000 0000 FPR7=0000000000000000 0000
XMM00=00000000000000000000000000000000 XMM01=00000000000000000000000000000000
XMM02=00000000000000000000000000000000 XMM03=00000000000000000000000000000000
XMM04=00000000000000000000000000000000 XMM05=00000000000000000000000000000000
XMM06=00000000000000000000000000000000 XMM07=00000000000000000000000000000000
kernel.c

Code: Select all

#include "terminal.h"

static int test; // Without this everything behaves as expected

int kmain() {
    test = 0;

    /* This function runs just fine unless a static variable is declared in terminal.c or here in kernel.c */
    some_function_from_terminal_h();
    for(;;);
    return 0;
}

boot.s

Code: Select all

.intel_syntax
.extern kmain

.set MAGIC_NUMBER, 0x1BADB002
.set FLAGS, 0X0
.set CHECKSUM, -(MAGIC_NUMBER + FLAGS)

.set KERNEL_STACK_SIZE, 16384 # 16 KiB

.section .multiboot
.align 4
.long MAGIC_NUMBER
.long FLAGS
.long CHECKSUM

# Reserve stack space for kernel
.section .bss
.align 16
stack_bottom:
.skip KERNEL_STACK_SIZE
stack_top:

.section .text
.global loader
loader:
        mov %esp, stack_top

        call kmain
loop:
        jmp loop
link.ld

Code: Select all

ENTRY(loader)

SECTIONS {
        . = 1M;

        .text BLOCK(4K) : ALIGN (4K)
        {
                *(.multiboot)
                *(.text)
        }

        .rodata BLOCK(4K) : ALIGN (4K)
        {
                *(.rodata)
        }

        .data BLOCK(4K) : ALIGN (4K)
        {
                *(.data)
        }

        .bss BLOCK(4K) : ALIGN (4K)
        {
                *(COMMON)
                *(.bss)
        }
}

Re: Error: Trying to execute code outside RAM

Posted: Sun Feb 12, 2017 4:49 am
by Love4Boobies
You are calling kmain but there is no reference of it. Instead, your C file declares a function call main. Limiting the visibility of your variable, which already has static storage since it is at file scope, isn't the issue. Your linker emits diagnostic messages precisely to avoid such silly problems.

Re: Error: Trying to execute code outside RAM

Posted: Sun Feb 12, 2017 12:33 pm
by MuchLearning
Love4Boobies wrote:You are calling kmain but there is no reference of it. Instead, your C file declares a function call main.
Excellent catch, but unfortunately that was just a typo I made writing the forum post last night. I came back and looked at the issue again this morning and realized I had missed another important step in reproducing the error, which was to include and call a function from another file along with declaring a static variable.

I am very appreciative of the time you took to read through everything the first time. I've gone through and updated the original question with more information and ensured that all the code I've supplied reproduces the error exactly as it is provided above.

Re: Error: Trying to execute code outside RAM

Posted: Sun Feb 12, 2017 12:51 pm
by heat
MuchLearning wrote:
Love4Boobies wrote:You are calling kmain but there is no reference of it. Instead, your C file declares a function call main.
Excellent catch, but unfortunately that was just a typo I made writing the forum post last night. I came back and looked at the issue again this morning and realized I had missed another important step in reproducing the error, which was to include and call a function from another file along with declaring a static variable.

I am very appreciative of the time you took to read through everything the first time. I've gone through and updated the original question with more information and ensured that all the code I've supplied reproduces the error exactly as it is provided above.
Use a cross-compiler, please. It might be the source of your issues.

Re: Error: Trying to execute code outside RAM

Posted: Sun Feb 12, 2017 1:58 pm
by MuchLearning
Error persists even when using cross compiler.

Re: Error: Trying to execute code outside RAM

Posted: Sun Feb 12, 2017 2:32 pm
by Roman
Try disassembling the kernel image with 'i686-elf-objdump -d'.

Re: Error: Trying to execute code outside RAM

Posted: Sun Feb 12, 2017 2:38 pm
by Octocontrabass

Code: Select all

ESP=fffffff0
Hm.

Code: Select all

.intel_syntax
Hmm.

Code: Select all

mov %esp, stack_top
Hmmmmmm.


There are several varieties of "Intel syntax". Which one are you using? Which one does GAS expect?

Re: Error: Trying to execute code outside RAM

Posted: Sun Feb 12, 2017 2:51 pm
by iansjack
Produce a linker map and inspect it for any possible overlaps/conflicts.

Re: Error: Trying to execute code outside RAM

Posted: Sun Feb 12, 2017 3:41 pm
by MuchLearning
With static int test

Code: Select all

Disassembly of section .text:

00100000 <loader-0xc>:
  100000:       02 b0 ad 1b 00 00       add    dh,BYTE PTR [eax+0x1bad]
  100006:       00 00                   add    BYTE PTR [eax],al
  100008:       fe 4f 52                dec    BYTE PTR [edi+0x52]
  10000b:       e4                      .byte 0xe4

0010000c <loader>:
  10000c:       8b 25 00 50 10 00       mov    esp,DWORD PTR ds:0x105000
  100012:       e8 09 00 00 00          call   100020 <kmain>

00100017 <loop>:
  100017:       eb fe                   jmp    100017 <loop>
  100019:       66 90                   xchg   ax,ax
  10001b:       66 90                   xchg   ax,ax
  10001d:       66 90                   xchg   ax,ax
  10001f:       90                      nop

00100020 <kmain>:
  100020:       83 ec 0c                sub    esp,0xc
  100023:       c7 05 00 50 10 00 00    mov    DWORD PTR ds:0x105000,0x0
  10002a:       00 00 00
  10002d:       e8 0e 00 00 00          call   100040 <some_function_from_terminal_h>
  100032:       eb fe                   jmp    100032 <kmain+0x12>
  100034:       66 90                   xchg   ax,ax
  100036:       66 90                   xchg   ax,ax
  100038:       66 90                   xchg   ax,ax
  10003a:       66 90                   xchg   ax,ax
  10003c:       66 90                   xchg   ax,ax
  10003e:       66 90                   xchg   ax,ax

00100040 <some_function_from_terminal_h>:
  100040:       f3 c3                   repz ret
Without static int test

Code: Select all

Disassembly of section .text:

00100000 <loader-0xc>:
  100000:       02 b0 ad 1b 00 00       add    dh,BYTE PTR [eax+0x1bad]
  100006:       00 00                   add    BYTE PTR [eax],al
  100008:       fe 4f 52                dec    BYTE PTR [edi+0x52]
  10000b:       e4                      .byte 0xe4

0010000c <loader>:
  10000c:       8b 25 00 50 10 00       mov    esp,DWORD PTR ds:0x105000
  100012:       e8 09 00 00 00          call   100020 <kmain>

00100017 <loop>:
  100017:       eb fe                   jmp    100017 <loop>
  100019:       66 90                   xchg   ax,ax
  10001b:       66 90                   xchg   ax,ax
  10001d:       66 90                   xchg   ax,ax
  10001f:       90                      nop

00100020 <kmain>:
  100020:       83 ec 0c                sub    esp,0xc
  100023:       e8 08 00 00 00          call   100030 <some_function_from_terminal_h>
  100028:       eb fe                   jmp    100028 <kmain+0x8>
  10002a:       66 90                   xchg   ax,ax
  10002c:       66 90                   xchg   ax,ax
  10002e:       66 90                   xchg   ax,ax

00100030 <some_function_from_terminal_h>:
  100030:       f3 c3                   repz ret

Not sure what is up with the weird xchg ax, ax instructions. Other than that the only difference between the two is the addition of these two lines in kmain.

Code: Select all

  100023:       c7 05 00 50 10 00 00    mov    DWORD PTR ds:0x105000,0x0
  10002a:       00 00 00
I assume the first line is trying to initialize the static int to 0, meaning it is stored at [DS + 0x105000] which from the first instruction in <loader> looks to be on the stack.
Not sure what is going on with the second line. Either way, still not sure how I end up trying to execute an instruction at such a crazy address.

Re: Error: Trying to execute code outside RAM

Posted: Sun Feb 12, 2017 3:51 pm
by MuchLearning
Octocontrabass wrote:

Code: Select all

ESP=fffffff0
Hm.

Code: Select all

.intel_syntax
Hmm.

Code: Select all

mov %esp, stack_top
Hmmmmmm.


There are several varieties of "Intel syntax". Which one are you using? Which one does GAS expect?
Based on this SO question I assumed .intel_syntax without being followed by no_prefix should look like the code provided.
Following the format instr dest, src and registers being denoted by %. Did I make a faulty assumption somewhere? It is somewhat difficult to find documentation for all of these things. Especially when you're not exactly sure what you are looking for.

From asm docs:
Good news are that starting from binutils 2.10 release, GAS supports Intel syntax too. It can be triggered with .intel_syntax directive. Unfortunately this mode is not documented (yet?) in the official binutils manual

Re: Error: Trying to execute code outside RAM

Posted: Sun Feb 12, 2017 3:56 pm
by iansjack
You appear to be loading your stack pointer from the contents of a memory location. The same location that stores your static variable.

Re: Error: Trying to execute code outside RAM

Posted: Sun Feb 12, 2017 4:15 pm
by MuchLearning
iansjack wrote:You appear to be loading your stack pointer from the contents of a memory location. The same location that stores your static variable.
How do I control where the system is putting static variables in memory? Where should they be going? Do I need to set aside memory for them somewhere in boot.s?

Re: Error: Trying to execute code outside RAM

Posted: Sun Feb 12, 2017 4:50 pm
by Octocontrabass
MuchLearning wrote:Based on this SO question I assumed .intel_syntax without being followed by no_prefix should look like the code provided.
Following the format instr dest, src and registers being denoted by %. Did I make a faulty assumption somewhere?
You're partially correct. Yes, the destination comes first, and yes, registers have the "%" prefix. The faulty assumption is in how labels are handled.

In NASM syntax, you need to explicitly specify when an operand is an immediate value or a memory reference. This means "mov eax, label" puts the address of the label in EAX, and "mov eax, [label]" puts the contents of the memory at that address into EAX.

In MASM and gas syntax, operands are automatically treated as immediate values or memory references depending on the type of the symbol. That means "mov eax, label" can load EAX with either the address of "label" or the contents of the memory at that address depending on how "label" was defined.

So!

When you say "mov $esp, stack_top", are you loading ESP with the address of the top of the stack, or the contents of the top of the stack?

MuchLearning wrote:It is somewhat difficult to find documentation for all of these things. Especially when you're not exactly sure what you are looking for.
You can get a pretty good idea of what to do by looking at the differences between MASM and NASM syntax.

Re: Error: Trying to execute code outside RAM

Posted: Sun Feb 12, 2017 4:59 pm
by iansjack
MuchLearning wrote:
iansjack wrote:You appear to be loading your stack pointer from the contents of a memory location. The same location that stores your static variable.
How do I control where the system is putting static variables in memory? Where should they be going? Do I need to set aside memory for them somewhere in boot.s?
That's not the problem. It's a question of loading the correct value into esp.