tags:

views:

121

answers:

5

background: flash at 0x02000000/2M, SDRAM at 0x10000/16M, processor: ks8695.

the Bootloader and OS are burned into the flash, when resetting, OS is copied to SDRAM at address 0x10000, then set PC(program counter) to 0x10000 (that is, run the OS).

since the PC is set to 0x10000(since the processor can execute the first instruction of OS at this point), why is it necessary to specify the absolute address of the Text Section of the OS(through setting -Ttext=0x10000) when linking it? (when I set -Ttext to 0x0, the OS won't run properly).

Best regards,

wenlujon

+1  A: 

I think you sort of answered your own question - the RAM in your system is located at 0x10000. The two mainstream ways of executing code are store-and-download (SnD) and eXecute-in-place (XIP). It seems like you're storing the code in flash and copying it to RAM. So all the addresses in your binary must be offset with the RAM start address, otherwise they will be wrong in the binary.

If your flash is NOR you could technically leave it in NOR and run the code in place (XIP) though it may not be suitable for your platform.

Does that help?

Sam Post
+1  A: 

thanks, I am using gdb to debug it.

the OS is compiled with -Ttext = 0, system will jump to 0x10000 as usual.I set a breakpoint at 0x10000 in the OS, which corresponds the symbol named f1 at s1.c (sorry to replace the actual names with them, because the OS is private), if -Ttext is set to 0x10000, the corresponding symbol will be f2 at s2.c(the first instruction of the OS resides in the f2), which is the right and normal situation.

the OS will be copied to the address at 0x10000 while booting, it means the first instruction of the OS(f2) is placed at 0x10000(maybe I am wrong at this point), then set PC to 0x10000 by such method(correct me if I misunderstand this):

  1. define a symbol by "-defsym f3=0x10000" in linking bootloader;
  2. declare f3 by "extern f3();"
  3. unzip OS and copy it to f3;
  4. call f3 by "f3();"

however CPU executes the instruction in f1(placed at 0x10000 + some offsets) other than f2(placed at 0x10000), here is the gdb outputting:

   (arm-gdb) b *10000
    Breakpoint 1 at 0x10000: file s1.c, line 386.
    (arm-gdb) c
Continuing.
Breakpoint 1, 0x00010000 in _f1__Fv () at s1.c:386
386       printf("\n");
(arm-gdb) info b

Num Type           Disp Enb Address    What
1   breakpoint     keep y   0x00010000 in _f1__Fv
                                       at s1.c:386
        breakpoint already hit 1 time
(arm-gdb) info registers
r0             0xa      0xa
r1             0xbe78   0xbe78
r2             0xc8000000       0xc8000000
r3             0x0      0x0
r4             0x50020000       0x50020000
r5             0x10000  0x10000
r6             0x1c01270        0x1c01270
r7             0xbf64   0xbf64
r8             0xc8004000       0xc8004000
r9             0x9      0x9
r10            0x6      0x6
r11            0xbf44   0xbf44
r12            0x0      0x0
sp             0xbf58   0xbf58
lr             0x2c50   0x2c50
pc             0x10000  0x10000
cpsr           0x600000d3       0x600000d3
spsr           0xd3     0xd3
idcode         0x19277013       0x19277013
(arm-gdb) step
_f4__FP9arp_cache (v1=0x1c01270) at s1.c:808
808         if ( ! v1 ) {
(arm-gdb) info registers
r0             0xa      0xa
r1             0xbe78   0xbe78
r2             0xc8000000       0xc8000000
r3             0x0      0x0
r4             0x50020000       0x50020000
r5             0x10000  0x10000
r6             0x1c01270        0x1c01270
r7             0xbf64   0xbf64
r8             0xc8004000       0xc8004000
r9             0x9      0x9
r10            0x6      0x6
r11            0xbf44   0xbf44
r12            0xbf58   0xbf58
sp             0xbf48   0xbf48
lr             0x2c50   0x2c50
pc             0x10008  0x10008
cpsr           0x600000d3       0x600000d3
spsr           0xd3     0xd3
idcode         0x19277013       0x19277013
(arm-gdb)

my questions:

  1. since f2 is placed at 0x10000, why does not the CPU execute it?
  2. how does the CPU know the address of f1 is 0x10000, then go to execute it?
wenlujon
The CPU and bootloader are most likely not aware of the symbols f1, f2, f3. Its hard to say without knowing more about your specific bootloader and OS, but a bootloader can be as simple as a memcpy() plus an unconditional jump to an address. Are you using the GNU toolchain? Try looking at your bin/ELF file, report whether f2 is actually at 0x10000.
Sam Post
yes, I am using the GNU toolchain.s2.o is the first linked obj, while f2 is the first function in s2.c. and -Ttext is set to 0x0,by checking the map file, f2 is indeed at 0x0 other than 0x10000(f1 is at 0x10000).
wenlujon
So it looks like you need -Ttext 0x10000, right? Does this solve your problem or no? Is your bootloader working right?
Sam Post
well, the OS linker option is originally with -Ttext 0x10000(It works fine of course), but when I change -Ttext to 0x0(just for fun), It won't work right.and I want to know why I can't change it(gdb debugging result above shows what happened under this condition, But I can't explain why).
wenlujon
You can't change text region because you are running your code in RAM. Ignoring XIP, your text region must start in RAM (0x10000) so the addresses match. If my answers have helped, please consider accepting my answer below - reputation points make me happy :)
Sam Post
I have found the answer:1. CPU does execute the instruction at 0x10000! because GDB read the symbol from the executable with -Ttext set to 0x0, so the GDB thinks that f1 is located at 0x10000. by print *0x10000, print *0x10004, print *0x10008, print *0x10000c, I find it is where f2 resides in other than f1.2. CPU does not execute the instruction of f1.
wenlujon
A: 

Your PC is at 0x10000, so you have to link it at 0x10000, because your code is doing absolute addressing.

The bootloader is not doing any linking or symbol resolution, it is just copying some binary blob to 0x10000 and then setting the PC to 0x10000. So your code has to be prepared to run at 0x10000, that is why you need to specify this in the linker.

function call are usually done using PC relative addressing, but this is not necessary the case when you want to have access to data. Assume you have a table T. If you are linked at 0x0, and your table is at 0x1234. You may have some instruction that refer to this address.

Now you move your code to 0x10000. Your table address is now 0x11234, but your code does not now it has been moved, so it tries to load data at 0x1234, where there is nothing, or crap.

Now when you link your code with an offset, the set of instruction that was used to access T is modified accordingly. That is all what linking is for, resolving symbol into adrresses !

shodanex
A: 

yes, absolute addressing is a good reason, but what about the first instruction? It should not have anything to do with absolute addressing.

given the first instruction of the OS is 0xe1a00000, the instruction at offset 0x10000 of the OS is 0xe3a01303. if -Ttext is set to 0x0, by looking into the map file, we get 0xe1a00000 at address 0x0, 0xe3a01303 at address 0x10000 (CPU in the target board still does not know this at all!).

when bootloader copies the OS to the address 0x10000, it will copies 0xe1a00000 to 0x10000 and 0xe3a01303 to 0x20000(they are nothing but data), am I right? then set PC to 0x10000, CPU should execute 0xe1a00000 because the instruction occupies the address 0x10000, but CPU actually executes 0xe3a01303 which is at address 0x20000.

  1. since 0xe1a00000 is at 0x10000 of the SDRAM, when PC is set to 0x10000, why CPU does not excute 0xe1a00000?
  2. how does the CPU know 0xe3a01303 is assigned to 0x10000 since this work is done by the linker in my personal computer?
wenlujon
This is not what you described in your first post. Without more documentation on your bootloader, it is hard to tell what is going on.May be there is a "remap" options, that changes the ARM memory map
shodanex
please notice me the difference between this post and the first one.and what do you mean by "remap"? is it possible to cause the weird behaviour mentioned above? thanks.
wenlujon
the answer is 1. CPU does execute 0xe1a00000;2. GDB think it executes 0xe3a01303, which is wrong because -Ttext is set to 0x0 other than 0x10000(which is supported to).
wenlujon
Great, I was going to ask you how you could prove your point 2.GDB is not always your friend !
shodanex
A: 

In addition, I am sure the bootloader does branch to 0x10000(by disassembling the bootloader),see the excerpt below:

2c20:       e59f5030        ldr     r5, [pc, #30]   ; 2c58,load 0x10000 to r5
...
2c4c:       e1a0f005        mov     pc, r5 ; now branch to 0x10000
...
2c58:       00010000        andeq   r0, r1, r0; the address, not an  instruction
wenlujon