Skip to content
This repository was archived by the owner on Jan 24, 2022. It is now read-only.

null dereference before main is called #21

Closed
japaric opened this issue Jun 30, 2017 · 5 comments · Fixed by #23
Closed

null dereference before main is called #21

japaric opened this issue Jun 30, 2017 · 5 comments · Fixed by #23

Comments

@japaric
Copy link
Member

japaric commented Jun 30, 2017

STR

#![feature(used)]
#![no_std]

extern crate cortex_m_rt;

fn main() {}

#[used]
#[link_section = ".rodata.interrupts"]
static INTERRUPTS: [u32; 240] = [0; 240];

with cortex-m-quickstart v0.1.8 and cortex-m-rt v0.2.4.

Produces:

08000400 <cortex_m_rt::reset_handler>:
 8000400:       b580            push    {r7, lr}
 8000402:       466f            mov     r7, sp
 8000404:       f240 0000       movw    r0, #0
 8000408:       f240 0100       movw    r1, #0
 800040c:       f2c2 0000       movt    r0, #8192       ; 0x2000
 8000410:       f2c2 0100       movt    r1, #8192       ; 0x2000
 8000414:       1a09            subs    r1, r1, r0
 8000416:       f021 0103       bic.w   r1, r1, #3
 800041a:       f000 f851       bl      80004c0 <__aeabi_memclr4>
 800041e:       f240 0000       movw    r0, #0
 8000422:       f240 0100       movw    r1, #0
 8000426:       f2c2 0000       movt    r0, #8192       ; 0x2000
 800042a:       f2c2 0100       movt    r1, #8192       ; 0x2000
 800042e:       1a09            subs    r1, r1, r0
 8000430:       f021 0203       bic.w   r2, r1, #3
 8000434:       f240 41d4       movw    r1, #1236       ; 0x4d4
 8000438:       f6c0 0100       movt    r1, #2048       ; 0x800
 800043c:       f000 f836       bl      80004ac <__aeabi_memcpy4>
 8000440:       f240 0000       movw    r0, #0
 8000444:       f2c0 0000       movt    r0, #0
 8000448:       7800            ldrb    r0, [r0, #0]
 800044a:       bf30            wfi
 800044c:       e7fd            b.n     800044a <cortex_m_rt::reset_handler+0x4a>

In this case there's no main to execute but this:

 8000440:       f240 0000       movw    r0, #0
 8000444:       f2c0 0000       movt    r0, #0
 8000448:       7800            ldrb    r0, [r0, #0]

is loading the byte stored at address 0x0. This doesn't crash on Cortex-M devices because that's a valid address (the start of the vector table).

I'm not exactly sure why that's being generated but it doesn't appear if I remove the start lang_item from cortex-m-rt and directly call a the binary crate main function.

cc @pftbest do you see something like this on msp430?

@pftbest
Copy link
Contributor

pftbest commented Jun 30, 2017

This code:

#![feature(used)]
#![no_std]

extern crate msp430_rt;

fn main() {}

#[used]
#[link_section = ".rodata.interrupts"]
static INTERRUPTS: [u16; 15] = [0; 15];

Gives me this assembly

0000c000 <msp430_rt::reset_handler::h9f6992508ddc1171>:
    c000:	31 40 00 04 	mov	#1024,	r1	;#0x0400
    c004:	30 40 08 c0 	br	#0xc008		;

0000c008 <msp430_rt::reset_handler::handler::hadc116d0dbef830c>:
    c008:	3c 40 00 02 	mov	#512,	r12	;#0x0200
    c00c:	3e 40 00 02 	mov	#512,	r14	;#0x0200
    c010:	0e 8c       	sub	r12,	r14	;
    c012:	3e f0 fe ff 	and	#65534,	r14	;#0xfffe
    c016:	3c 40 00 02 	mov	#512,	r12	;#0x0200
    c01a:	0d 43       	clr	r13		;
    c01c:	b0 12 54 c0 	call	#49236		;#0xc054 (memset)
    c020:	3c 40 00 02 	mov	#512,	r12	;#0x0200
    c024:	3e 40 00 02 	mov	#512,	r14	;#0x0200
    c028:	0e 8c       	sub	r12,	r14	;
    c02a:	3e f0 fe ff 	and	#65534,	r14	;#0xfffe
    c02e:	3c 40 00 02 	mov	#512,	r12	;#0x0200
    c032:	3d 40 68 c0 	mov	#49256,	r13	;#0xc068
    c036:	b0 12 3c c0 	call	#49212		;#0xc03c (memcpy)

0000c03a <.LBB2_1>:
    c03a:	ff 3f       	jmp	$+0      	;abs 0xc03a

It looks all right, not reading any memory at all, just infinite loop.

@japaric
Copy link
Member Author

japaric commented Jul 1, 2017

@pftbest Thanks for checking.

I looked at the llvm-ir and I think I see the problem:

; Function Attrs: nounwind
define i32 @main(i32, i8** nocapture readnone) unnamed_addr #0 {
top:
  %2 = load volatile i8, i8* getelementptr inbounds ([34 x i8], [34 x i8]* @__rustc_debug_gdb_scripts_section__, i32 0, i32 0), align 1
  tail call void @llvm.dbg.value(metadata i32 0, i64 0, metadata !1297, metadata !1313) #7, !dbg !1314
  tail call void @llvm.dbg.value(metadata i8** null, i64 0, metadata !1308, metadata !1313) #7, !dbg !1314
  tail call void @llvm.dbg.value(metadata i32 0, i64 0, metadata !1311, metadata !1313) #7, !dbg !1315
  tail call void @llvm.dbg.value(metadata i8** null, i64 0, metadata !1312, metadata !1313) #7, !dbg !1316
  tail call fastcc void @_ZN4core9panicking5panic17hbfa03ee93bef2b09E() #7, !dbg !1317
  unreachable, !dbg !1317
}

IIRC the rustc compiler injects this volatile load of the rustc_debug_gdb_scripts_section symbol / section so that the debug information is not discarded by ... LLVM? In any case this is a rustc hack. The fact that I'm seeing a load of the address 0x0 is that in #7 (cc @whitequark) we changed the linker script so that the .debug_gdb_scripts section is not loaded in flash and to do that we used INFO and placed the section at a ficticious address 0x0.

It'd be great to not have this weird load in the first place but if it must be kept around maybe it would be better to change the load address from 0x0 to something that we are certain will never trigger a hard fault (perhaps 0x0 is OK, IDK).

@pftbest that's the disassembly that you got from compiling your program in release mode but without debug information, right? Could you try enabling debuginfo for the release profile in Cargo.toml (see below) and see if the output changes?

[profile.release]
debug = true

@whitequark
Copy link
Contributor

IIRC the rustc compiler injects this volatile load of the rustc_debug_gdb_scripts_section symbol / section so that the debug information is not discarded by ... LLVM?

No. It's done so that you can just run gdb on your ELF file and have gdb load the scripts that imbue gdb with the knowledge of Rust. The debug information itself is completely decoupled from this.

It'd be great to not have this weird load in the first place but if it must be kept around maybe it would be better to change the load address from 0x0 to something that we are certain will never trigger a hard fault (perhaps 0x0 is OK, IDK).

Yeah... any chance you could place it, for example, right at the beginning of .text or .rodata? I think that's the only clean solution I see.

@whitequark
Copy link
Contributor

As a side note: with this linker script we actually don't need the rustc hack, but we can't turn it off either. Welp.

@pftbest
Copy link
Contributor

pftbest commented Jul 1, 2017

@japaric , wow, when debug is enabled i can see the load

    c03a:	b0 12 44 c0 	call	#49220		;#0xc044
    c03e:	5c 42 00 00 	mov.b	&0x0000,r12	;0x0000

0000c042 <.LBB2_1>:
    c042:	ff 3f       	jmp	$+0      	;abs 0xc042

rukai pushed a commit to rukai/cortex-m-rt that referenced this issue May 1, 2021
21: note the code of conduct in the README r=japaric a=japaric

Testing PR builds

Co-authored-by: Jorge Aparicio <[email protected]>
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants