So i have a simple linker script for my stm32f7 mcu
MEMORY{
ROM_AXIM (rx) : ORIGIN = 0x08000000, LENGTH = 1M
ROM_ITCM (rx) : ORIGIN = 0x00200000, LENGTH = 1M
RAM_ITCM (rwx): ORIGIN = 0x00000000, LENGTH = 16K
RAM_DTCM (rwx): ORIGIN = 0x20000000, LENGTH = 64K
SRAM (rwx): ORIGIN = 0x20010000, LENGTH = 240K
SRAM2 (rwx): ORIGIN = 0x2004C000, LENGTH = 16K
}
_estack = LENGTH(RAM_DTCM) + ORIGIN(RAM_DTCM);
SECTIONS{
.isr_vector : {
KEEP(*(.isr_vector))
} /* Placed at 0x0 */
.text : {
. = ALIGN(4);
*(.text)
} >ROM_ITCM
.data : {
. = ALIGN(4);
_sdata = .;
*(.data)
. = ALIGN(4);
_sdata = .;
} >SRAM2 AT>ROM_AXIM
.bss : {
. = ALIGN(4);
_sbss = .;
*(.bss)
. = ALIGN(4);
_ebss = .;
} >SRAM2
}
The idea is to place text section to ROM_ITCM because instruction fetching is accelerated with ART accelerator. But the problem is that ROM_AXIM and ROM_ITCM is the same flash storage. How to tell linker that is physically same storage but accessed on separate buses. So it links like it is two separate buses, but the text section should actually follow .isr_vector immediately in memory and offset is taken into account
For example, here is my bin file that will go to flash:
00000000 00 00 01 20 01 00 20 00 00 00 00 00 00 00 00 00 |... .. .........|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00200000 00 20 70 47 |. pG|
00200004
As you can see a lot flash is wasted and it ill try to write this bin beyond flash boundary as well.
VS:
00000000 00 00 01 20 09 00 00 08 00 20 70 47
0000000c
this hexdump, is what i am looking for but, as you can see Reset_Handler has address of AXIM bus. What i want to do is by using the linker script provided above to get an output like this:
00000000 00 00 01 20 09 00 20 00 00 20 70 47
0000000c
The difference here is that it will use 0x00200008 to look for my reset handler.
What i have tried so far:
.text : {
. = ALIGN(4);
*(.text)
} >ROM_ITCM AT>ROM_AXIM
This one would work, but the problem is that it will give this output
00000000 00 00 01 20 01 00 20 00 00 20 70 47 |... .. .. pG|
0000000c
which will load instruction at 0x00200000 and by doing that it will load first entry of vector table (stack pointer) as an instruction
I managed to solve a problem by consulting a gnu linker page. What i did was to specify runtime offset of a section like this.
.text (0x00200000 + SIZEOF(.isr_vector)): {
. = ALIGN(4);
*(.text)
} AT>ROM_AXIM
What it does is:
.text (0x00200000 + SIZEOF(.isr_vector)) specify run-time address with an offset of vector table size. my pointers are now resolved correctly
AT>ROM_AXIM places the code right after vector table which produced the offset in first place. and above line fixes it.
-
Related
I need to make firmware image with 8K size. Firmware image should have a version word at the end. Area between data section and version section must be filled with 0xFF.
This linker script works fine if test and data sections not too big.
MEMORY
{
PM_RAM (rwx): ORIGIN = 0x00000000, LENGTH = 20K
DM_RAM (rwx) : ORIGIN = 0x0001E000, LENGTH = 6K
PM_ROM (rx) : ORIGIN = 0x00080000, LENGTH = 256K
PM_OTP (rx): ORIGIN = 0x000C0000, LENGTH = 8K - VERSION_SIZE
PM_OTP_VER (rx): ORIGIN = 0x000C0000 + 8K - VERSION_SIZE, LENGTH = VERSION_SIZE
}
SECTIONS {
.text :
{
*(.text*)
. = ALIGN(4);
} >PM_OTP
_etext = .;
.data : {
_sdata = .;
_ldata = LOADADDR(.data);
*(.data .data.*)
*(.sdata .sdata.*)
. = ALIGN(4);
} >DM_RAM AT>PM_OTP
. = ALIGN(4);
_edata = .;
.fill : {
BYTE(0xFF)
FILL(0xFF)
. = LENGTH(PM_OTP) - SIZEOF(.text) - SIZEOF(.data) - 1;
} > PM_OTP = 0xFF
.version : {
. = ALIGN(4);
__version_start__ = .;
KEEP(*(.version .version*))
__version_end__ = .;
} > PM_OTP_VER
.bss : {
_sbss = .;
*(.bss .bss.*)
. = ALIGN(4);
*(.sbss .sbss.*)
. = ALIGN(4);
} >DM_RAM
. = ALIGN(4);
_ebss = .;
_end = .;
.stack ORIGIN(DM_RAM) + LENGTH(DM_RAM) - STACK_SIZE : {
PROVIDE(__STACK_START__ = .);
. += STACK_SIZE;
PROVIDE(__C_STACK_TOP__ = .);
} >DM_RAM
}
But if text + data close to 8K I get the error:
cannot move location counter backwards (from 00000000000c2095 to 00000000000c1ffb)
If change this string:
. = LENGTH(PM_OTP) - SIZEOF(.text) - SIZEOF(.data) - 1;
by hardcoded value like:
. = 0x3f;
Build completes successfully and all OK.
What is wrong with LENGTH(PM_OTP) - SIZEOF(.text) - SIZEOF(.data) calculations?
In listing file it corresponds to 0x3f.
UPDATE
I have linker script
STACK_SIZE = 1024;
TEST_MEMORY_SIZE = 4;
VERSION_SIZE = 4;
MEMORY
{
PM_RAM (rwx): ORIGIN = 0xFD000000, LENGTH = 120K
DM_RAM (rwx) : ORIGIN = 0xFD01E000, LENGTH = 6K
PM_ROM (rx) : ORIGIN = 0xFD080000, LENGTH = 256K
PM_OTP (rx): ORIGIN = 0xFD0C0000, LENGTH = 8K - VERSION_SIZE
PM_OTP_VER (rx): ORIGIN = 0xFD0C0000 + 8K - VERSION_SIZE, LENGTH = VERSION_SIZE
}
SECTIONS {
.init ORIGIN(PM_OTP):
{
. = 0x000;
*(.init.startup)
. = ALIGN(4);
*(.init.traphandler)
. = ALIGN(4);
} >PM_OTP
.text :
{
*(.text*)
. = ALIGN(4);
*(.text.emulate*)
. = ALIGN(4);
*(.rodata .rodata.*)
. = ALIGN(4);
} >PM_OTP
_etext = .;
.data : {
_sdata = .;
_ldata = LOADADDR(.data);
*(.data .data.*)
*(.sdata .sdata.*)
. = ALIGN(4);
} >DM_RAM AT>PM_OTP
. = ALIGN(4);
_edata = .;
.fill :
{
BYTE(0xFF)
FILL(0xFF)
} > PM_OTP = 0xFF
.version :
{
. = ALIGN(4);
__version_start__ = .;
KEEP(*(.version .version*))
__version_end__ = .;
} > PM_OTP_VER
.bss : {
_sbss = .;
*(.bss .bss.*)
. = ALIGN(4);
*(.sbss .sbss.*)
. = ALIGN(4);
} >DM_RAM
. = ALIGN(4);
_ebss = .;
_end = .;
.stack ORIGIN(DM_RAM) + LENGTH(DM_RAM) - STACK_SIZE : {
PROVIDE(__STACK_START__ = .);
. += STACK_SIZE;
PROVIDE(__C_STACK_TOP__ = .);
} >DM_RAM
_test_memory = ORIGIN(DM_RAM) + LENGTH(DM_RAM);
_loader_descr = _test_memory + TEST_MEMORY_SIZE;
}
Build terminates successfully and I get:
text data bss dec hex
7700 321 1056 9077 2375
Binary look:
00001f10 94 05 0c fd 98 05 0c fd 9c 05 0c fd a0 05 0c fd |................|
00001f20 a4 05 0c fd a8 05 0c fd 00 00 00 00 00 00 00 00 |................|
00001f30 00 00 00 00 ac 05 0c fd 00 00 00 00 00 00 00 00 |................|
00001f40 00 00 00 00 00 00 00 00 00 00 00 00 01 01 00 00 |................|
00001f50 ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00001f60 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00001ff0 00 00 00 00 00 00 00 00 00 00 00 00 60 b8 ee 61 |............`..a|
00002000
There are zeros here from 00001f60 to the end. But I need 0xFF.
I added line:
. = LENGTH(PM_OTP) - SIZEOF(.init) - SIZEOF(.text) - SIZEOF(.data);`
In setion .fill after FILL(0xFF) and got error:
cannot move location counter backwards (from 00000000fd0c2025 to 00000000fd0c1ffc)
Very strange. But ok. I gradually reduce my code volume. And at a certain code decrease, the build begins to be successful.
text data bss dec hex
7656 536 1056 9248 2420
Binary look:
00001ef0 a0 05 0c fd a4 05 0c fd a8 05 0c fd 00 00 00 00 |................|
00001f00 00 00 00 00 00 00 00 00 ac 05 0c fd 00 00 00 00 |................|
00001f10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00001f20 01 01 00 00 ff ff ff ff ff ff ff ff ff ff ff ff |................|
00001f30 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
*
00001ff0 ff ff ff ff ff ff ff ff ff ff ff ff 50 bb ee 61 |............P..a|
00002000
There is a lot of 0xFF in the end. And offset is correctly calculated, because 0xFF goes up to version. But other side 0xFF is empty area that could be filled with useful code.
0x00000000000c2095 is apparently beyond PM_OTP (rx): ORIGIN = 0x000C0000, LENGTH = 8K - VERSION_SIZE. Your firmware is too large.
I'm playing with tail calls feature of BPF, and it seems the simple code doesn't get loaded:
struct bpf_map_def SEC("maps") jmp_table = {
.type = BPF_MAP_TYPE_PROG_ARRAY,
.key_size = sizeof(u32),
.value_size = sizeof(u32),
.max_entries = 8,
};
SEC("sockops")
int bpf1(struct bpf_sock_ops *sk_ops)
{
return 1;
}
SEC("sockops")
int bpf2(struct bpf_sock_ops *sk_ops)
{
return 1;
}
SEC("sockops")
int bpf3(struct bpf_sock_ops *sk_ops)
{
return 1;
}
SEC("sockops")
int bpf_main(struct bpf_sock_ops *sk_ops)
{
__u32 port = bpf_ntohl(sk_ops->remote_port);
switch (port) {
case 5000:
bpf_tail_call(sk_ops, &jmp_table, 1);
break;
case 6000:
bpf_tail_call(sk_ops, &jmp_table, 2);
break;
case 7000:
bpf_tail_call(sk_ops, &jmp_table, 3);
break;
}
sk_ops->reply = 0;
return 1;
}
char _license[] SEC("license") = "GPL";
u32 _version SEC("version") = LINUX_VERSION_CODE;
So I compiled it with llv-3.8 and loaded with bpftool:
$ sudo ./bpftool prog load bpf_main.o /sys/fs/bpf/p1
libbpf: load bpf program failed: Invalid argument
libbpf: -- BEGIN DUMP LOG ---
libbpf:
unreachable insn 2
libbpf: -- END LOG --
libbpf: failed to load program 'sockops'
libbpf: failed to load object 'bpf_main.o'
Error: failed to load program
So man 2 bpf mentions that:
EINVAL For BPF_PROG_LOAD, indicates an attempt to load an invalid program. eBPF programs can be deemed invalid due to unrecognized instructions, the use of reserved fields, jumps out of range, infinite loops or calls of unknown functions.
I don't see what is wrong with this tiny simple program, also llvm-objdump fails:
$ llvm-objdump-3.8 -arch-name=bpf -disassemble ./tcp_metrics_kern.o
./tcp_metrics_kern.o: file format ELF64-unknown
LLVM ERROR: error: no disassembler for target bpfel-unknown-unknown
UPDATE 1
Following Qeole's advice I upgraded to clang-5.0, rebuilt my program and now it complains differently:
$ sudo ./bpftool prog load bpf_main.o /sys/fs/bpf/p1
libbpf: relocation failed: no 10 section
Error: failed to load program
Now I can investigate ELF sections:
$ llvm-objdump-5.0 -disassemble -source ./bpf_main.o
./bpf_main.o: file format ELF64-BPF
Disassembly of section sockops:
bpf1:
0: b7 00 00 00 01 00 00 00 r0 = 1
1: 95 00 00 00 00 00 00 00 exit
bpf2:
2: b7 00 00 00 01 00 00 00 r0 = 1
3: 95 00 00 00 00 00 00 00 exit
bpf3:
4: b7 00 00 00 01 00 00 00 r0 = 1
5: 95 00 00 00 00 00 00 00 exit
bpf_main:
...
Here are available sections:
$ llvm-objdump-5.0 -section-headers ./bpf_main.o
./bpf_main.o: file format ELF64-BPF
Sections:
Idx Name Size Address Type
0 00000000 0000000000000000
1 .strtab 000000a5 0000000000000000
2 .text 00000000 0000000000000000 TEXT DATA
3 sockops 000001f8 0000000000000000 TEXT DATA
4 .relsockops 00000030 0000000000000000
5 maps 0000001c 0000000000000000 DATA
6 .rodata.str1.16 00000021 0000000000000000 DATA
7 .rodata.str1.1 0000000e 0000000000000000 DATA
8 license 00000004 0000000000000000 DATA
9 version 00000004 0000000000000000 DATA
10 .eh_frame 00000090 0000000000000000 DATA
11 .rel.eh_frame 00000040 0000000000000000
12 .symtab 00000138 0000000000000000
It looks that bpftool can't find section .eh_frame?
UPDATE 2
I continue experimenting :-) First of all I updated libbpf with latest commit d77be68955475fc2321e73fe006240248f2f8fef fixing string comparison, then I rebuild the program with -fno-asynchronous-unwind-tables, this does not include .eh_frame section, and also I gave unique section names, e.g. sockops0, sockops1 etc. Now bpftool prog load .. succeeds but bpftool prog show dumps only a single program, the one that goes very first, in my case it is bpf1().
At the moment I can say that bpf_object__load_progs() reports obj->nr_programs as 4, this makes sense for my example.
I like the linux kernel module_init function very much, I would like to implement the same function for my user space applications.
I try to modify the linker script to do this:
1, copy a x86-64 standard ld script
2, add my customized section
.module.init :
{
PROVIDE_HIDDEN (__module_init_start = .);
*(.module_init*)
PROVIDE_HIDDEN (__module_init_end = .);
}
3, put the init function pointer into moudle_init section
#define app_module_init(x) __initcall(x);
#define __initcall(fn) \
static initcall_t __initcall_##fn \
__attribute__ ((__section__(".module_init"))) = fn
app_module_init(unit_test_1_init);
app_module_init(unit_test_2_init);
app_module_init(unit_test_3_init);
app_module_init(unit_test_4_init);
4, compile the app with a customized linker script(based on the standard one)
gcc -o "./module_init" -T module.lds ./module_init.o
5, Then I objdump the moudle_init, I found the section is generated:
Disassembly of section .module_init:
0000000000a01080 <__initcall_unit_test_1_init>:
a01080: ad lods %ds:(%rsi),%eax
a01081: 05 40 00 00 00 add $0x40,%eax
...
0000000000a01088 <__initcall_unit_test_2_init>:
a01088: c2 05 40 retq $0x4005
a0108b: 00 00 add %al,(%rax)
a0108d: 00 00 add %al,(%rax)
...
0000000000a01090 <__initcall_unit_test_3_init>:
a01090: d7 xlat %ds:(%rbx)
a01091: 05 40 00 00 00 add $0x40,%eax
...
0000000000a01098 <__initcall_unit_test_4_init>:
a01098: ec in (%dx),%al
a01099: 05 40 00 00 00 add $0x40,%eax
But the __module_init_start and __module_init_end variable is not the value I expected. In my case __module_init_start is 0x4005ad and __module_init_end is 0x400000003.
This is very weird, because 0x4005ad is the address of __initcall_unit_test_1_init.
Anyone can give me an idea on how to make this user space module_init work?
The linker script can only set the addresses of variables. Use &__module_init_start to get a pointer to the start of the section, and &__module_init_end to get a pointer to the end.
Test platform is on 32 bit Linux.
Here is my code:
#include <stdio.h>
#include "calc_mean.h"
extern double mean(double, double);
extern int aaaa;
static int b;
static int c = 999999999;
static double d;
static float e = 2.0;
static double f = 2.0;
int main(int argc, char* argv[]) {
double v1, v2, m;
v1 = 5.2;
v2 = 7.9;
aaaa = 100;
b = 123;
c = 321;
d = 13.3;
e = 122.2;
e = 123123.123;
f = 11231233.0;
f = 111233.0;
f = 1133.0;
f = 11231231231233.0;
e = 33.4;
printf("%d\n", aaaa);
printf("asdfjkhadsfkjhadskfjh\n");
printf("adsjfhaskdjfhakjdshfkajhdsfkjahdfkjh%d\n", aaaa);
m = mean(v1, v2);
printf("The mean of %3.2f and %3.2f is %3.2f\n", v1, v2, m);
return 0;
}
I use objdump to dump the .data section's content, and here are the info I got.
objdump -s -j .data test
dump info
test: file format elf32-i386
Contents of section .data:
804a018 00000000 00000000 ffc99a3b 00000040 ...........;...#
804a028 00000000 00000040 .......#
Then another method:
objdump -D test > dump
here is the .data section in dump
Disassembly of section .data:
0804a018 <__data_start>:
804a018: 00 00 add %al,(%eax)
...
0804a01c <__dso_handle>:
804a01c: 00 00 add %al,(%eax)
...
0804a020 <c>:
804a020: ff c9 dec %ecx
804a022: 9a 3b 00 00 00 40 00 lcall $0x40,$0x3b
0804a024 <e>:
804a024: 00 00 add %al,(%eax)
804a026: 00 40 00 add %al,0x0(%eax)
0804a028 <f>:
804a028: 00 00 add %al,(%eax)
804a02a: 00 00 add %al,(%eax)
804a02c: 00 00 add %al,(%eax)
804a02e: 00 .byte 0x0
804a02f: 40 inc %eax
So what I am trying to do is obtaining the variable info(like variable name, length, value) from the dump(and probably with disassembly) info I present
But currently I don't know how to obtain the type info from the dump file, and I think without the type information, I can hardly know the length as well as value of each variable...
Could anyone give me some help?
THank you!
Variable information such as variable name, address, size etc. is usually compiled as DWARF information in the executable. It will only be available when you compile your code with -g flag. Look for section names starting with .dwarf when using objdump or similar tools.
I have a simple code that I am trying to compile with lm32-rtems4.11-gcc.
I have the code, the compile command and the lst below. When I compile I see a bunch of code added on the top instead of the startup code that I want in there. The code I want the processor to start with after reset is at location 3f4 instead of 0. What I wanted help on is to figure out how the rest of the code got in and find a way to remove it or move all that code to addresses after my code. I appreciate the help.
Thanks
The code:
//FILE: crt.S
.globl _start
.text
_start:
xor r0, r0, r0
mvhi sp, hi(_fstack)
ori sp, sp, lo(_fstack)
mv fp,r0
mvhi r1, hi(_fbss)
ori r1, r1, lo(_fbss)
mvhi r2, hi(_ebss)
ori r2, r2, lo(_ebss)
1:
bge r1, r2, 2f
sw (r1+0), r0
addi r1, r1, 4
bi 1b
2:
calli main
mvhi r1, 0xdead
ori r2, r0, 0xbeef
sw (r1+0), r2
//FILE: hello_world.c
void putc(char c)
{
char *tx = (char*)0xff000000;
*tx = c;
}
void puts(char *s)
{
while (*s) putc(*s++);
}
void main(void)
{
puts("Hello World\n");
}
//FILE: linker.ld
OUTPUT_FORMAT("elf32-lm32")
ENTRY(_start)
__DYNAMIC = 0;
MEMORY {
pmem : ORIGIN = 0x00000000, LENGTH = 0x8000
dmem : ORIGIN = 0x00008000, LENGTH = 0x8000
}
SECTIONS
{
.text :
{
_ftext = .;
*(.text .stub .text.* .gnu.linkonce.t.*)
_etext = .;
} > pmem
.rodata :
{
. = ALIGN(4);
_frodata = .;
*(.rodata .rodata.* .gnu.linkonce.r.*)
*(.rodata1)
_erodata = .;
} > dmem
.data :
{
. = ALIGN(4);
_fdata = .;
*(.data .data.* .gnu.linkonce.d.*)
*(.data1)
_gp = ALIGN(16);
*(.sdata .sdata.* .gnu.linkonce.s.*)
_edata = .;
} > dmem
.bss :
{
. = ALIGN(4);
_fbss = .;
*(.dynsbss)
*(.sbss .sbss.* .gnu.linkonce.sb.*)
*(.scommon)
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(4);
_ebss = .;
_end = .;
} > dmem
}
The compile command
lm32-rtems4.11-gcc -Tlinker.ld -fno-builtin -o hello_world.elf crt.S hello_world.c
lm32-rtems4.11-objdump -DS hello_world.lst hello_world.elf
The lst file
00000000 <rtems_provides_crt0>:
#include <signal.h> /* sigset_t */
#include <time.h> /* struct timespec */
#include <unistd.h> /* isatty */
void rtems_provides_crt0( void ) {} /* dummy symbol so file always has one */
0: c3 a0 00 00 ret
00000004 <rtems_stub_malloc>:
#define RTEMS_STUB(ret, func, body) \
ret rtems_stub_##func body; \
ret func body
/* RTEMS provides some of its own routines including a Malloc family */
RTEMS_STUB(void *,malloc(size_t s), { return 0; })
4: 34 01 00 00 mvi r1,0
8: c3 a0 00 00 ret
0000000c <malloc>:
c: 34 01 00 00 mvi r1,0
10: c3 a0 00 00 ret
.
.
.
//omitting other such unrelated code that was inserted into the code and going to the
//code at 3f4 that is the code I wanted at 0
000003f0 <__assert_func>:
3f0: c3 a0 00 00 ret
000003f4 <_start>:
3f4: 98 00 00 00 xor r0,r0,r0
3f8: 78 1c 00 00 mvhi sp,0x0
3fc: 3b 9c ff fc ori sp,sp,0xfffc
400: b8 00 d8 00 mv fp,r0
404: 78 01 00 00 mvhi r1,0x0
408: 38 21 84 48 ori r1,r1,0x8448
40c: 78 02 00 00 mvhi r2,0x0
410: 38 42 84 48 ori r2,r2,0x8448
414: 4c 22 00 04 bge r1,r2,424 <_start+0x30>
418: 58 20 00 00 sw (r1+0),r0
41c: 34 21 00 04 addi r1,r1,4
420: e3 ff ff fd bi 414 <_start+0x20>
424: f8 00 00 28 calli 4c4 <main>
428: 78 01 de ad mvhi r1,0xdead
42c: 38 02 be ef mvu r2,0xbeef
430: 58 22 00 00 sw (r1+0),r2
.
.
.
As far as the .elf object you have generated is concerned, execution starts from 0x3f4, not from location 0. That's a result of your linker map specifying the entry point as the _start symbol. Whatever parses the .elf object should jump to that location when transferring execution to the program.
Now, perhaps an .elf object is not what you want to end up with - if the result isn't to be loaded by something which knows how to parse an .elf object, then you may need some other format, such as a flat binary image.
It's quite common when using a gcc elf toolchain with a small embedded chip to turn the .elf object into a flat binary using a command along the lines of
toolchain-prefix-objcopy -O binary something.elf something.bin
It's also possible you may need to create some sort of stub to jump to the _start label, and adjust your linker map to make sure that is the first thing in the image.
More generally though, you can probably find a working example for this toolchain and either this processor or a comparable one. Setting up embedded build systems from scratch is a bit tricky, so don't do it the hard way if there's any chance of finding an example to follow.
So I could not figure out why the compiler does not move the .start label to 0 when the linker.ld clearly tells it to do so. But I did figure a work around.
I created a section name for the startup code as shown in BOLD below. I then created a section in memory starting at 0 which I reserved only for this start up code. That seemed to do the trick. I ran the code and got a hello world :) . All the changes I made are in BOLD and also commented //Change 1 //Change 2 and //Change 3.
//FILE: crt.S
.section .init// Change 1
.globl _start
.text
_start:
xor r0, r0, r0
mvhi sp, hi(_fstack)
ori sp, sp, lo(_fstack)
mv fp,r0
mvhi r1, hi(_fbss)
ori r1, r1, lo(_fbss)
.
.
//linker.ld
OUTPUT_FORMAT("elf32-lm32")
ENTRY(_start)
__DYNAMIC = 0;
MEMORY {
init : ORIGIN = 0x00000000, LENGTH = 0x40 //Change 2
pmem : ORIGIN = 0x00000040, LENGTH = 0x8000
dmem : ORIGIN = 0x00008000, LENGTH = 0x8000
}
SECTIONS
{
.init : {*(.init)}>init //Change 3
.text :
{
_ftext = .;
*(.text .stub .text.* .gnu.linkonce.t.*)
_etext = .;
} > pmem