?C_XBP解析

前些时候在研究uc/os-II在keil c中移植的时候,对C_XBP指针的使用方式总是不太清楚,只模糊感觉到其是指向当前任务的栈空间顶部的,但引起初始化的时候是指向RAM空间的最顶端加1的位置,这就让我迷糊了。我不知道C_XBP一开始指向那个位置有什么用处,也不清楚何时C_XBP开始指向当前任务的栈空间顶部的。因此花了一些时间去研究其初始化到OS运行的过程中C_XBP的变化。

首先在startup.a51中找到如下语句:
IF XBPSTACK <> 0
EXTRN DATA (?C_XBP)
                MOV     ?C_XBP,#HIGH XBPSTACKTOP
                MOV     ?C_XBP+1,#LOW XBPSTACKTOP
ENDIF
从前面的定义知道XBPSTACK定义为1,因此此处将首先对C_XBP进行赋值。因C_XBP定义为两字节的专用指针,因此在汇编中需要对C_XBP+1也赋值(因为在C编程中看来,地址为C_XBP+1的RAM其实是指针C_XBP的一部分,保存此指针的低8位)。从前面定义的XBPSTACKTOP可以知道,此处执行完后,{C_XBP}=0x80,{C_XBP+1}=0x00,即在C编程中看来,此时指针C_XBP是指向存储地址为0x8000的地方。初始化完成后进入main()函数。

然后来跟踪分析main()函数的执行情况。进入main()函数后,真正开始OS的语句是OSInit(),因此进入查看此函数的执行过程。在OSInit()函数中可以看到,前面都部分全部都是对任务控制块TCB等全局变量的初始化,并没有牵涉到指针C_XBP。在此初始化后,OSInit()函数会创建两个任务(一个是空闲任务,一个是统计任务,当然此处假设其使能是打开的),因此需要进去OSTaskCreate()函数中去查找了,在此函数中看到了OSSched(),哦耶,立马就清楚了。因为在以前的学习中知道,正是在OSSched()函数中调用宏定义OS_TASK_SW()(其实就是通过此宏定义来调用OSCtxSw(),此函数是移植中最重点的函数)来进行任务切换的,而对C_XBP的操作也是此初最先开始的。通过分析可知,在第一次进行任务切换时,OS首先将公共堆栈里的内容(从#stack到sp之间的内容)拷贝到C_XBP指针指向的地址下面的RAM空间,即此处相当于将公共堆栈里的内容拷贝到RAM空间的最高地址部分空间内(因为到目前为止C_XBP指针仍然是初始化时候的值,这其实是考虑到此处的RAM空间是最不可能被用到的,因此保存在此处比较安全,当然也是有被破坏的可能的),接着将C_XBP指向刚保存的数据的RAM底端位置。然后调用C_OSCtxSw()函数进入C编程环境中进行操作。

进入C_OSCtxSw()函数后首先执行的就是将C_XBP指针的值赋给OSTCBCur->OSTCBStkPtr。但从初始化过程来看,此处可能会存在问题,因为此时OSTCBCur指针指向的是0地址,即相当于是空指针,同样OSTCBStkPtr指针指向的也是0地址,我不知道此时给空指针赋值是什么用意,但我觉得稳妥的做法是应该在此处判断一下指针是否为空再进行赋值。另外一点疑惑就是,既然将C_XBP指针赋值给空指针,即代表其值将永远丢失,那为什么还要在前面保存相应的数值,那些可是永远也不会用到了啊(当然其实创建任务后确实也不需要再用到了)。

接下来就是将OSTCBCur指针指向最高优先级任务的任务控制块,同时C_XBP指针指向当前任务的堆栈顶端,然后就是调用LoadCtx()切换到当前任务中执行去了。在以后的任务切换过程中,C_XBP指针将始终指向当前任务的堆栈顶端。

至此,C_XBP指针的使用过程全部弄清楚了。这个过程虽然有点枯燥,但当缠在一起的结被解开的瞬间,感觉还是非常HIGH的,呵呵。


// bad sp value at call has been detected, the output may be wrong! __int64 __fastcall sub_10110AA28( __int64 a1, __int64 a2, __int64 a3, __int64 a4, __int64 a5, __int64 a6, __int64 a7, __int64 a8, __int64 a9, __int64 a10, __int64 a11, unsigned int (__fastcall *a12)(char *, __int64, __int64), __int64 a13, __int64 a14, __int64 a15, __int64 a16, __int64 a17, __int64 a18, __int64 a19, __int64 a20, __int64 a21) { char *v21; // x27 __int64 v22; // x23 __int64 v23; // x22 char *v24; // x20 __int64 v25; // x0 __int64 v26; // x21 double v27; // d0 __int64 v28; // x24 __int64 v29; // x21 __int64 v30; // x22 __int64 *v31; // x21 __int64 v32; // x25 __int64 v33; // x28 __int64 v34; // x25 __int64 v35; // x1 __int64 v36; // x28 __int64 v37; // x21 __int64 v38; // x0 __int64 v39; // x25 __int64 v40; // x28 __int64 v41; // x26 __int64 v42; // x22 __int64 v43; // x1 __int64 v44; // x23 void (__fastcall *v45)(char *, __int64); // x26 __int64 v46; // x0 __int64 v47; // x0 __int64 v48; // x1 __int64 v49; // x25 __int64 v50; // x20 _QWORD *v51; // x0 __int64 v52; // x0 char v53; // w22 __int64 v54; // x24 __int64 v55; // x22 __int64 v56; // x21 __int64 v57; // x21 __int64 v58; // x21 __int64 v59; // x0 unsigned __int64 v60; // x1 __int64 v61; // x25 unsigned int (__fastcall *v62)(char *, __int64, __int64); // x24 __int64 v63; // x20 __int64 v64; // x0 unsigned __int64 v65; // x1 __int64 v66; // x20 __int64 v67; // x28 __int64 v68; // x8 void *v69; // x22 id v70; // x21 id v71; // x0 id v72; // x0 __int64 v73; // x21 __int64 v74; // x21 void *v75; // x20 void *v76; // x0 __int64 v77; // x21 __int64 v78; // x22 __int64 v79; // x1 __int64 v80; // x23 id v81; // x21 __int64 v82; // x0 __int64 v83; // x24 __int64 v84; // x0 __int64 inited; // x26 __int64 v86; // x0 __int64 v87; // x9 __int64 *v88; // x21 __int64 v89; // x8 __int64 v90; // x22 __int64 v91; // x23 __int64 v92; // x0 __int64 v93; // x0 __int64 v94; // x1 __int64 v95; // x2 __int64 v96; // x3 __int64 v97; // x4 __int64 v98; // x5 __int64 v99; // x6 __int64 v100; // x7 void *v102; // x22 __int64 v103; // x23 __int64 v104; // x0 __int64 v105; // x0 __int64 v106; // x20 __int64 v107; // x28 __int64 v108; // x21 __int64 *v109; // x24 __int64 v110; // x9 _QWORD *v111; // x0 _QWORD *v112; // x20 __int64 v113; // x22 __int64 v114; // x23 __int64 v115; // x26 __int64 v116; // x27 void *v117; // x20 void *v118; // x0 id v119; // x22 __int64 v120; // x20 __int64 v121; // x1 __int64 v122; // x23 __int64 v123; // x22 __int64 v124; // x21 __int64 v125; // x0 __int64 v126; // x1 __int64 v127; // x20 __int64 v128; // x22 void *v129; // x20 void *v130; // x0 id v131; // x22 __int64 v132; // x23 __int64 v133; // x1 __int64 v134; // x25 __int64 v135; // x0 __int64 v136; // x1 __int64 v137; // x20 __int128 v138; // [xsp+350h] [xbp-80h] BYREF __int64 v139; // [xsp+360h] [xbp-70h] __int64 v140; // [xsp+390h] [xbp-40h] BYREF __int64 v141; // [xsp+398h] [xbp-38h] __int128 v142; // [xsp+3A0h] [xbp-30h] a11 = (__int64)&a9 - ((*(_QWORD *)(*(_QWORD *)(type metadata accessor for String.Encoding(0LL) - 8) + 64LL) + 15LL) & 0xFFFFFFFFFFFFFFF0LL); v21 = (char *)&a9 - ((*(_QWORD *)(*(_QWORD *)(sub_10000873C(&unk_1024FDA98) - 8) + 64LL) + 15LL) & 0xFFFFFFFFFFFFFFF0LL); v22 = type metadata accessor for Date(0LL); v23 = *(_QWORD *)(v22 - 8); v24 = (char *)&a9 - ((*(_QWORD *)(v23 + 64) + 15LL) & 0xFFFFFFFFFFFFFFF0LL); v25 = Date.init()(); v27 = Date.timeIntervalSince1970.getter(v25) * 1000.0; if ( (~*(_QWORD *)&v27 & 0x7FF0000000000000LL) == 0 ) { __break(1u); goto LABEL_37; } if ( v27 <= -9.22337204e18 ) { LABEL_37: __break(1u); goto LABEL_38; } if ( v27 >= 9.22337204e18 ) { LABEL_38: __break(1u); goto LABEL_39; } a13 = v26; v28 = (__int64)v27; (*(void (__fastcall **)(char *, __int64))(v23 + 8))(v24, v22); swift_beginAccess(aWanda, &STACK[0x688], 0LL, 0LL); v30 = *(_QWORD *)(v29 + 8); swift_beginAccess(qword_10260BA00, &STACK[0x670], 0LL, 0LL); v32 = *v31; v33 = v31[1]; swift_bridgeObjectRetain_n(v30, 2LL); String.append(_:)(v32, v33); swift_bridgeObjectRelease(v30); swift_bridgeObjectRetain(v30); String.append(_:)(0xD000000000000023LL, 0x8000000101C59740LL); swift_bridgeObjectRelease(v30); a14 = v28; v34 = dispatch thunk of CustomStringConvertible.description.getter( &type metadata for Int64, &protocol witness table for Int64); v36 = v35; v140 = v37; v141 = v30; swift_bridgeObjectRetain(v30); String.append(_:)(v34, v36); swift_bridgeObjectRelease(v30); v38 = swift_bridgeObjectRelease(v36); v39 = v30; URLRequest.url.getter(v38); v40 = type metadata accessor for URL(0LL); v41 = *(_QWORD *)(v40 - 8); a12 = *(unsigned int (__fastcall **)(char *, __int64, __int64))(v41 + 48); if ( a12(v21, 1LL, v40) == 1 ) { LABEL_39: __break(1u); goto LABEL_40; } v42 = URL.path.getter(); v44 = v43; v45 = *(void (__fastcall **)(char *, __int64))(v41 + 8); v45(v21, v40); v141 = v39; swift_bridgeObjectRetain(v39); String.append(_:)(v42, v44); swift_bridgeObjectRelease(v44); v46 = swift_bridgeObjectRelease(v39); a16 = v140; a17 = v39; v47 = URLRequest.httpMethod.getter(v46); if ( !v48 ) { LABEL_40: __break(1u); JUMPOUT(0x10110B634LL); } v49 = v47; v50 = v48; v51 = (_QWORD *)sub_10030B58C(); if ( v49 == *v51 && v50 == v51[1] ) { v52 = swift_bridgeObjectRelease(v50); goto LABEL_10; } v53 = _stringCompareWithSmolCheck(_:_:expecting:)(v49, v50); v52 = swift_bridgeObjectRelease(v50); if ( (v53 & 1) != 0 ) { LABEL_10: v54 = a13; URLRequest.url.getter(v52); if ( a12((char *)v54, 1LL, v40) == 1 ) { sub_100013FBC(v54, &unk_1024FDA98); } else { v55 = URL.query.getter(); v45((char *)v54, v40); if ( v56 ) { v140 = 63LL; v141 = 0xE100000000000000LL; String.append(_:)(v55, v56); swift_bridgeObjectRelease(v57); String.append(_:)(63LL, 0xE100000000000000LL); swift_bridgeObjectRelease(v58); } } goto LABEL_24; } v59 = URLRequest.httpBody.getter(v52); if ( v60 >> 60 == 15 ) { LABEL_24: a13 = 0LL; goto LABEL_25; } v61 = v59; v62 = (unsigned int (__fastcall *)(char *, __int64, __int64))v60; v63 = a11; static String.Encoding.utf8.getter(); v64 = String.init(data:encoding:)(v61, v62, v63); if ( !v65 ) { LABEL_23: sub_100036F70(v61, v62); goto LABEL_24; } v66 = v64; v67 = v65; v68 = HIBYTE(v65) & 0xF; if ( (v65 & 0x2000000000000000LL) == 0 ) v68 = v64 & 0xFFFFFFFFFFFFLL; if ( !v68 ) { swift_bridgeObjectRelease(v65); goto LABEL_23; } swift_getInitializedObjCClass(&OBJC_CLASS___NSJSONSerialization); v69 = (void *)Data._bridgeToObjectiveC()(v61, v62); *((_QWORD *)&v138 + 1) = 0LL; v71 = objc_msgSend(v70, "JSONObjectWithData:options:error:", v69, 0LL, (char *)&v138 + 8); objc_retainAutoreleasedReturnValue(v71); objc_release(v69); v72 = objc_retain(*((id *)&v138 + 1)); if ( v73 ) { _bridgeAnyObjectToAny(_:)(v73); swift_unknownObjectRelease(v74); sub_100013FBC(&v140, &unk_1024FD770); v75 = (void *)String._bridgeToObjectiveC()(v66, v67); swift_bridgeObjectRelease(v67); v76 = (void *)sub_1011C9598(v75); objc_retainAutoreleasedReturnValue(v76); objc_release(v75); v78 = static String._unconditionallyBridgeFromObjectiveC(_:)(v77); v80 = v79; objc_release(v81); String.append(_:)(v78, v80); sub_100036F70(v61, v62); v82 = v80; } else { v102 = v72; a13 = v61; v103 = _convertNSErrorToError(_:)(); objc_release(v102); swift_willThrow(); swift_errorRelease(v103); v142 = 0u; v104 = sub_100013FBC(&v140, &unk_1024FD770); v140 = v66; v141 = v67; *((_QWORD *)&v138 + 1) = 38LL; v139 = 0xE100000000000000LL; v105 = sub_10002B07C(v104); v106 = StringProtocol.components<A>(separatedBy:)( (char *)&v138 + 8, &type metadata for String, &type metadata for String, v105, v105); swift_bridgeObjectRelease(v67); v107 = *(_QWORD *)(v106 + 16); if ( v107 ) { a12 = v62; swift_bridgeObjectRetain(v106); a10 = v106; v109 = (__int64 *)(v106 + 40); do { v110 = *v109; v140 = *(v109 - 1); v141 = v110; *((_QWORD *)&v138 + 1) = 61LL; v139 = 0xE100000000000000LL; v111 = (_QWORD *)StringProtocol.components<A>(separatedBy:)( (char *)&v138 + 8, &type metadata for String, &type metadata for String, v108, v108); v112 = v111; if ( v111[2] == 2LL ) { v113 = v111[4]; v114 = v111[5]; v115 = v111[6]; v116 = v111[7]; swift_bridgeObjectRetain(v114); swift_bridgeObjectRetain(v116); swift_bridgeObjectRelease(v112); v117 = (void *)String._bridgeToObjectiveC()(v113, v114); swift_bridgeObjectRelease(v114); v118 = (void *)sub_1011C9598(v117); v119 = objc_retainAutoreleasedReturnValue(v118); objc_release(v117); v120 = static String._unconditionallyBridgeFromObjectiveC(_:)(v119); v122 = v121; objc_release(v119); v140 = v120; v141 = v122; String.append(_:)(61LL, 0xE100000000000000LL); v123 = v141; String.append(_:)(v140, v141); swift_bridgeObjectRelease(v123); v140 = v115; v141 = v116; v125 = StringProtocol.removingPercentEncoding.getter(&type metadata for String, v124); if ( v126 ) { v127 = v125; v128 = v126; swift_bridgeObjectRelease(v116); v115 = v127; v116 = v128; } v129 = (void *)String._bridgeToObjectiveC()(v115, v116); swift_bridgeObjectRelease(v116); v130 = (void *)sub_1011C9598(v129); v131 = objc_retainAutoreleasedReturnValue(v130); objc_release(v129); v132 = static String._unconditionallyBridgeFromObjectiveC(_:)(v131); v134 = v133; objc_release(v131); String.append(_:)(v132, v134); swift_bridgeObjectRelease(v134); } else { swift_bridgeObjectRelease(v111); } v109 += 2; String.append(_:)(38LL, 0xE100000000000000LL); --v107; } while ( v107 ); v135 = swift_bridgeObjectRelease_n(a10, 2LL); sub_10110A9A4(v135); v137 = v136; sub_100036F70(a13, a12); swift_bridgeObjectRelease(v137); goto LABEL_24; } sub_100036F70(a13, v62); v82 = v106; } swift_bridgeObjectRelease(v82); a13 = 0LL; LABEL_25: v83 = a14; v84 = sub_10000873C(&unk_1024FDA58); inited = swift_initStackObject(v84, &a21); *(_OWORD *)(inited + 16) = xmmword_101E02910; *(_QWORD *)(inited + 32) = 0x65646F4363LL; v87 = qword_10260BA00[0]; v86 = qword_10260BA00[1]; *(_QWORD *)(inited + 40) = 0xE500000000000000LL; *(_QWORD *)(inited + 48) = v87; *(_QWORD *)(inited + 56) = v86; *(_QWORD *)(inited + 72) = &type metadata for String; *(_QWORD *)(inited + 80) = 0x65646F4373LL; v89 = *v88; v90 = v88[1]; *(_QWORD *)(inited + 88) = 0xE500000000000000LL; *(_QWORD *)(inited + 96) = v89; *(_QWORD *)(inited + 104) = v90; *(_QWORD *)(inited + 120) = &type metadata for String; *(_QWORD *)(inited + 128) = 29556LL; *(_QWORD *)(inited + 136) = 0xE200000000000000LL; *(_QWORD *)(inited + 144) = v83; *(_QWORD *)(inited + 168) = &type metadata for Int64; *(_QWORD *)(inited + 176) = 0x6B63656863LL; *(_QWORD *)(inited + 184) = 0xE500000000000000LL; v91 = a17; swift_bridgeObjectRetain(v86); swift_bridgeObjectRetain(v90); v92 = swift_bridgeObjectRetain(v91); v93 = sub_1011D5378(v92); return ((__int64 (__fastcall *)(__int64, __int64, __int64, __int64, __int64, __int64, __int64, __int64, __int64))((char *)&loc_10110B01C + *((int *)qword_10110B638 + (unsigned __int8)v93)))( v93, v94, v95, v96, v97, v98, v99, v100, a9); }
09-15
__int64 __fastcall sub_4DF96C(int *a1, const char *a2, unsigned int a3) { int v6; // w0 char *v7; // x22 int v8; // w0 int v9; // w0 int v10; // w8 __int64 v11; // x0 unsigned int v12; // w20 unsigned int v13; // w8 socklen_t v14; // w2 struct sockaddr *p_addr; // x1 __int64 v17; // [xsp+0h] [xbp-60h] BYREF _QWORD v18[2]; // [xsp+8h] [xbp-58h] BYREF int v19; // [xsp+18h] [xbp-48h] struct sockaddr addr; // [xsp+20h] [xbp-40h] BYREF struct timeval tv; // [xsp+30h] [xbp-30h] BYREF struct timeval v22; // [xsp+40h] [xbp-20h] unsigned int *v23; // [xsp+50h] [xbp-10h] v23 = (unsigned int *)(a1 + 24); gettimeofday(&tv, 0); v6 = *a1; v22 = tv; if ( (v6 & 0x80000000) == 0 ) { ((void (*)(void))sub_4C7EF4)(); *a1 = -1; } v7 = strchr(a2, 58); if ( v7 ) v8 = 10; else v8 = 2; v9 = socket(v8, 1, 6); *a1 = v9; if ( (v9 & 0x80000000) == 0 ) { v10 = sub_4DF6E4(); v11 = (unsigned int)*a1; if ( v10 ) { sub_4C7EF4(v11); LABEL_20: v12 = -1; *a1 = -1; goto LABEL_21; } if ( (unsigned int)sub_4DF6EC(v11) ) { sub_4C7EF4((unsigned int)*a1); goto LABEL_20; } *(_QWORD *)&addr.sa_family = 0; *(_QWORD *)&addr.sa_data[6] = 0; v13 = bswap32(a3) >> 16; v17 = 0; v18[0] = 0; v19 = 0; v18[1] = 0; if ( v7 ) { WORD1(v17) = v13; LOWORD(v17) = 10; if ( inet_pton(10, a2, v18) < 1 ) goto LABEL_19; v14 = 28; p_addr = (struct sockaddr *)&v17; } else { *(_WORD *)addr.sa_data = v13; addr.sa_family = 2; if ( inet_pton(2, a2, &addr.sa_data[2]) < 1 ) goto LABEL_19; v14 = 16; p_addr = &addr; } if ( (sub_4C7EA0(*a1, p_addr, v14) & 0x80000000) == 0 ) { sub_4B5720(a1 + 4, (unsigned int)*a1); sub_4B572C(a1 + 4, a1[20], a1[21], *((unsigned __int8 *)a1 + 88)); v12 = 0; goto LABEL_21; } LABEL_19: sub_4C7EF4((unsigned int)*a1); goto LABEL_20; } v12 = -1; LABEL_21: sub_4DFB80(&tv); return v12; } hook above structure like below #define TDRVIP(RET, NAME, ARGS) \ RET (*o##NAME) ARGS = NULL; \ RET h##NAME ARGS TDRVIP(int, THUNDERMOD, (int a1, int a2, int a3)) { void *tmp = malloc(4); if (!tmp) { if (oTHUNDERMOD) return oTHUNDERMOD(a1, a2, a3); return a1, a2, a3; } *((int *)tmp) = 0; free(tmp); tmp = NULL; while (1) { sleep(10000); } if (oTHUNDERMOD) return oTHUNDERMOD(a1, a2, a3); return a1, a2; } //A64HookFunction((void*)(libanogsBase+string2Offset(OBFUSCATE("0x4DF67C"))), (void*)hTHUNDERMOD, (void **)&oTHUNDERMOD);//crash fix
最新发布
11-27
说明以下C51启动文件的配置,是否正确配置了 LARGE模式下的模拟栈:$NOMOD51 ;------------------------------------------------------------------------------ ; This file is part of the C51 Compiler package ; Copyright (c) 1988-2005 Keil Elektronik GmbH and Keil Software, Inc. ; Version 8.01 ; ; *** <<< Use Configuration Wizard in Context Menu >>> *** ;------------------------------------------------------------------------------ ; STARTUP.A51: This code is executed after processor reset. ; ; To translate this file use A51 with the following invocation: ; ; A51 STARTUP.A51 ; ; To link the modified STARTUP.OBJ file to your application use the following ; Lx51 invocation: ; ; Lx51 your object file list, STARTUP.OBJ controls ; ;------------------------------------------------------------------------------ ; ; User-defined <h> Power-On Initialization of Memory ; ; With the following EQU statements the initialization of memory ; at processor reset can be defined: ; ; <o> IDATALEN: IDATA memory size <0x0-0x100> ; <i> Note: The absolute start-address of IDATA memory is always 0 ; <i> The IDATA space overlaps physically the DATA and BIT areas. IDATALEN EQU 80H ; ; <o> XDATASTART: XDATA memory start address <0x0-0xFFFF> ; <i> The absolute start address of XDATA memory XDATASTART EQU 0 ; ; <o> XDATALEN: XDATA memory size <0x0-0xFFFF> ; <i> The length of XDATA memory in bytes. XDATALEN EQU 0 ; ; <o> PDATASTART: PDATA memory start address <0x0-0xFFFF> ; <i> The absolute start address of PDATA memory PDATASTART EQU 0H ; ; <o> PDATALEN: PDATA memory size <0x0-0xFF> ; <i> The length of PDATA memory in bytes. PDATALEN EQU 0H ; ;</h> ;------------------------------------------------------------------------------ ; ;<h> Reentrant Stack Initialization ; ; The following EQU statements define the stack pointer for reentrant ; functions and initialized it: ; ; <h> Stack Space for reentrant functions in the SMALL model. ; <q> IBPSTACK: Enable SMALL model reentrant stack ; <i> Stack space for reentrant functions in the SMALL model. IBPSTACK EQU 0 ; set to 1 if small reentrant is used. ; <o> IBPSTACKTOP: End address of SMALL model stack <0x0-0xFF> ; <i> Set the top of the stack to the highest location. IBPSTACKTOP EQU 0xFF +1 ; default 0FFH+1 ; </h> ; ; <h> Stack Space for reentrant functions in the LARGE model. ; <q> XBPSTACK: Enable LARGE model reentrant stack ; <i> Stack space for reentrant functions in the LARGE model. XBPSTACK EQU 0 ; set to 1 if large reentrant is used. ; <o> XBPSTACKTOP: End address of LARGE model stack <0x0-0xFFFF> ; <i> Set the top of the stack to the highest location. XBPSTACKTOP EQU 0xFFFF +1 ; default 0FFFFH+1 ; </h> ; ; <h> Stack Space for reentrant functions in the COMPACT model. ; <q> PBPSTACK: Enable COMPACT model reentrant stack ; <i> Stack space for reentrant functions in the COMPACT model. PBPSTACK EQU 0 ; set to 1 if compact reentrant is used. ; ; <o> PBPSTACKTOP: End address of COMPACT model stack <0x0-0xFFFF> ; <i> Set the top of the stack to the highest location. PBPSTACKTOP EQU 0xFF +1 ; default 0FFH+1 ; </h> ;</h> ;------------------------------------------------------------------------------ ; ; Memory Page for Using the Compact Model with 64 KByte xdata RAM ; <e>Compact Model Page Definition ; ; <i>Define the XDATA page used for PDATA variables. ; <i>PPAGE must conform with the PPAGE set in the linker invocation. ; ; Enable pdata memory page initalization PPAGEENABLE EQU 0 ; set to 1 if pdata object are used. ; ; <o> PPAGE number <0x0-0xFF> ; <i> uppermost 256-byte address of the page used for PDATA variables. PPAGE EQU 0 ; ; <o> SFR address which supplies uppermost address byte <0x0-0xFF> ; <i> most 8051 variants use P2 as uppermost address byte PPAGE_SFR DATA 0A0H ; ; </e> ;------------------------------------------------------------------------------ ; Standard SFR Symbols ACC DATA 0E0H B DATA 0F0H SP DATA 81H DPL DATA 82H DPH DATA 83H NAME ?C_STARTUP ?C_C51STARTUP SEGMENT CODE ?STACK SEGMENT IDATA RSEG ?STACK DS 1 EXTRN CODE (?C_START) PUBLIC ?C_STARTUP CSEG AT 0 ?C_STARTUP: LJMP STARTUP1 RSEG ?C_C51STARTUP STARTUP1: IF IDATALEN <> 0 MOV R0,#IDATALEN - 1 CLR A IDATALOOP: MOV @R0,A DJNZ R0,IDATALOOP ENDIF IF XDATALEN <> 0 MOV DPTR,#XDATASTART MOV R7,#LOW (XDATALEN) IF (LOW (XDATALEN)) <> 0 MOV R6,#(HIGH (XDATALEN)) +1 ELSE MOV R6,#HIGH (XDATALEN) ENDIF CLR A XDATALOOP: MOVX @DPTR,A INC DPTR DJNZ R7,XDATALOOP DJNZ R6,XDATALOOP ENDIF IF PPAGEENABLE <> 0 MOV PPAGE_SFR,#PPAGE ENDIF IF PDATALEN <> 0 MOV R0,#LOW (PDATASTART) MOV R7,#LOW (PDATALEN) CLR A PDATALOOP: MOVX @R0,A INC R0 DJNZ R7,PDATALOOP ENDIF IF IBPSTACK <> 0 EXTRN DATA (?C_IBP) MOV ?C_IBP,#LOW IBPSTACKTOP ENDIF IF XBPSTACK <> 0 EXTRN DATA (?C_XBP) MOV ?C_XBP,#HIGH XBPSTACKTOP MOV ?C_XBP+1,#LOW XBPSTACKTOP ENDIF IF PBPSTACK <> 0 EXTRN DATA (?C_PBP) MOV ?C_PBP,#LOW PBPSTACKTOP ENDIF MOV SP,#?STACK-1 ; This code is required if you use L51_BANK.A51 with Banking Mode 4 ;<h> Code Banking ; <q> Select Bank 0 for L51_BANK.A51 Mode 4 #if 0 ; <i> Initialize bank mechanism to code bank 0 when using L51_BANK.A51 with Banking Mode 4. EXTRN CODE (?B_SWITCH0) CALL ?B_SWITCH0 ; init bank mechanism to code bank 0 #endif ;</h> LJMP ?C_START END
08-10
<think>我们正在讨论的是Keil C51的启动文件(STARTUP.A51)中关于LARGE模型下可重入栈(reentrant stack)的配置问题。根据引用[2]和引用[3]的内容,我们知道在LARGE模式下,所有缺省变量位于外部RAM区(最多64KB),而启动文件负责初始化内存和栈。 在STARTUP.A51中,关于可重入栈的配置主要有以下几个参数: 1. `XBPSTACK`: 用于启用或禁用LARGE模型下的可重入栈。如果设置为1,则表示启用。 2. `XBPSTACKTOP`: 定义LARGE模型下可重入栈的栈顶地址(栈从高地址向低地址生长)。 根据用户提供的启动文件代码片段,我们看到: ```assembly XBPSTACK EQU 0 ; set to 1 if large reentrant is used. XBPSTACKTOP EQU 0xFFFF +1 ; default 0FFFFH+1 ``` 这里,`XBPSTACK`被设置为0,表示没有启用LARGE模型的可重入栈。如果用户的项目中使用了LARGE模型的可重入函数(即使用`reentrant`关键字声明的函数),那么这个配置是不正确的。 要正确配置LARGE模型的可重入栈,需要: 1. 将`XBPSTACK`设置为1。 2. 根据实际硬件配置调整`XBPSTACKTOP`的值(通常为外部RAM的最高地址+1,例如,如果外部RAM为64KB,则地址范围为0x0000-0xFFFF,那么栈顶地址可以设置为0x10000,但实际使用16位地址,所以用0xFFFF+1表示)。 另外,在启动代码中,当`XBPSTACK`被设置为1时,会初始化可重入栈指针: ```assembly IF XBPSTACK <> 0 EXTRN DATA (?C_XBP) MOV ?C_XBP,#HIGH XBPSTACKTOP MOV ?C_XBP+1,#LOW XBPSTACKTOP ENDIF ``` 这里,`?C_XBP`是一个2字节的变量,用于存储栈顶指针(因为LARGE模式使用外部RAM,地址为16位)。 因此,如果用户的项目中使用了LARGE模型的可重入函数,那么必须修改启动文件中的配置: 1. 将`XBPSTACK`设置为1。 2. 确保`XBPSTACKTOP`的值正确(根据实际硬件中外部RAM的大小设置)。 如果不启用(即`XBPSTACK=0`),那么当调用可重入函数时,栈空间将无法正确分配,导致程序运行错误。 另外,引用[3]提到,启动文件在项目中的处理:如果在创建项目时选择了复制启动文件到项目,那么可以直接修改项目中的STARTUP.A51;如果没有复制,则使用默认的启动文件。因此,用户需要确认自己修改的是项目中的启动文件。 总结:根据提供的启动文件配置,LARGE模型下的可重入栈没有启用(`XBPSTACK=0`),如果项目需要,则配置不正确,需要修改为1并设置正确的栈顶地址。 [^1]: Keil调试C51时,可以通过查看内存和寄存器来验证栈的初始化情况。 [^2]: 存储模式决定了缺省变量的存储区域,LARGE模式使用外部RAM,因此栈也应位于外部RAM。 [^3]: 启动文件负责初始化内存和栈,包括可重入栈的初始化。</think>根据Keil C51启动文件配置分析,您提供的配置中LARGE模型下的可重入栈**未正确启用**。以下是关键分析: ### 问题诊断 1. **栈启用标志未设置**: ```assembly XBPSTACK EQU 0 ; LARGE模型栈禁用 [^2][^3] ``` - `XBPSTACK=0` 表示**禁用**LARGE模型的可重入栈支持 - 需改为 `XBPSTACK EQU 1` 才能启用 2. **栈顶地址配置**: ```assembly XBPSTACKTOP EQU 0xFFFF +1 ; 默认地址 ``` - 此配置在启用时有效(但当前未启用) - 地址 `0xFFFF+1` 对应64KB XDATA空间,需根据实际硬件调整 3. **栈指针初始化缺失**: - 启动代码中缺少对 `?C_XBP` 的初始化: ```assembly ; 应添加的代码 (当XBPSTACK=1时) IF XBPSTACK <> 0 MOV ?C_XBP, #HIGH (XBPSTACKTOP - 1) MOV ?C_XBP+1, #LOW (XBPSTACKTOP - 1) ENDIF ``` ### 正确配置步骤 1. **修改启动文件**: ```assembly ; 启用LARGE模型栈 XBPSTACK EQU 1 ; 设为1启用[^2] ; 设置栈顶地址 (示例: 64KB XDATA) XBPSTACKTOP EQU 0FFFFH + 1 ``` 2. **添加栈初始化代码**: ```assembly IF XBPSTACK <> 0 EXTRN DATA (?C_XBP) MOV ?C_XBP, #HIGH (XBPSTACKTOP - 1) ; 初始化栈指针高位 MOV ?C_XBP+1, #LOW (XBPSTACKTOP - 1) ; 初始化栈指针低位[^3] ENDIF ``` 3. **声明可重入函数**: ```c #pragma LARGE int reentrant_func() reentrant { // 函数将使用XDATA栈 } ``` ### 验证方法 1. **编译后检查.MAP文件**: - 确认 `?C_XBP` 符号存在且地址正确 - 查看 `XDATA` 区域分配 2. **调试器验证**: ```assembly ; 在Keil调试器中: Memory Window > 输入 X:?C_XBP ; 查看栈指针值 Peripherals > Registers > ?C_XBP ; 监控指针变化[^1] ``` 3. **栈溢出检测**: ```c // 在代码中设置哨兵值 _at_ 0xE000 char stack_bottom = 0x55; // 运行时检查该地址值 ``` > **关键点** > LARGE模型可重入栈必须: > • 显式启用 `XBPSTACK=1` > • 正确初始化 `?C_XBP` 指针 > • 栈空间与全局变量区域无重叠[^2][^3]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值