mirror of
https://github.com/mytechnotalent/Embedded-Hacking.git
synced 2026-09-09 11:29:03 +02:00
Added stack tutorial
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
build
|
||||
!.vscode/*
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Pico",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**",
|
||||
"${userHome}/.pico-sdk/sdk/2.3.0/**"
|
||||
],
|
||||
"forcedInclude": [
|
||||
"${workspaceFolder}/build/generated/pico_base/pico/config_autogen.h",
|
||||
"${userHome}/.pico-sdk/sdk/2.3.0/src/common/pico_base_headers/include/pico.h"
|
||||
],
|
||||
"defines": [],
|
||||
"compilerPath": "${userHome}/.pico-sdk/toolchain/15_2_Rel1/bin/arm-none-eabi-gcc.exe",
|
||||
"compileCommands": "${workspaceFolder}/build/compile_commands.json",
|
||||
"cStandard": "c17",
|
||||
"cppStandard": "c++14",
|
||||
"intelliSenseMode": "linux-gcc-arm"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
[
|
||||
{
|
||||
"name": "Pico",
|
||||
"compilers": {
|
||||
"C": "${command:raspberry-pi-pico.getCompilerPath}",
|
||||
"CXX": "${command:raspberry-pi-pico.getCxxCompilerPath}"
|
||||
},
|
||||
"environmentVariables": {
|
||||
"PATH": "${command:raspberry-pi-pico.getEnvPath};${env:PATH}"
|
||||
},
|
||||
"cmakeSettings": {
|
||||
"Python3_EXECUTABLE": "${command:raspberry-pi-pico.getPythonPath}"
|
||||
}
|
||||
}
|
||||
]
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"marus25.cortex-debug",
|
||||
"ms-vscode.cpptools",
|
||||
"ms-vscode.cpptools-extension-pack",
|
||||
"ms-vscode.vscode-serial-monitor",
|
||||
"raspberry-pi.raspberry-pi-pico"
|
||||
]
|
||||
}
|
||||
Vendored
+52
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Pico Debug (Cortex-Debug)",
|
||||
"cwd": "${userHome}/.pico-sdk/openocd/0.12.0+dev/scripts",
|
||||
"executable": "${command:raspberry-pi-pico.launchTargetPath}",
|
||||
"request": "launch",
|
||||
"type": "cortex-debug",
|
||||
"servertype": "openocd",
|
||||
"serverpath": "${userHome}/.pico-sdk/openocd/0.12.0+dev/openocd.exe",
|
||||
"gdbPath": "${command:raspberry-pi-pico.getGDBPath}",
|
||||
"debuggerArgs": ["-ex", "set debug-file-directory /debug"],
|
||||
"device": "${command:raspberry-pi-pico.getChipUppercase}",
|
||||
"configFiles": [
|
||||
"interface/cmsis-dap.cfg",
|
||||
"target/${command:raspberry-pi-pico.getTarget}.cfg"
|
||||
],
|
||||
"svdFile": "${userHome}/.pico-sdk/sdk/2.3.0/src/${command:raspberry-pi-pico.getChip}/hardware_regs/${command:raspberry-pi-pico.getChipUppercase}.svd",
|
||||
"runToEntryPoint": "main",
|
||||
// Fix for no_flash binaries, where monitor reset halt doesn't do what is expected
|
||||
// Also works fine for flash binaries
|
||||
"overrideLaunchCommands": [
|
||||
"monitor reset init",
|
||||
"load \"${command:raspberry-pi-pico.launchTargetPath}\""
|
||||
],
|
||||
"openOCDLaunchCommands": [
|
||||
"adapter speed 5000"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Pico Debug (Cortex-Debug with external OpenOCD)",
|
||||
"cwd": "${workspaceRoot}",
|
||||
"executable": "${command:raspberry-pi-pico.launchTargetPath}",
|
||||
"request": "launch",
|
||||
"type": "cortex-debug",
|
||||
"servertype": "external",
|
||||
"gdbTarget": "localhost:3333",
|
||||
"gdbPath": "${command:raspberry-pi-pico.getGDBPath}",
|
||||
"debuggerArgs": ["-ex", "set debug-file-directory /debug"],
|
||||
"device": "${command:raspberry-pi-pico.getChipUppercase}",
|
||||
"svdFile": "${userHome}/.pico-sdk/sdk/2.3.0/src/${command:raspberry-pi-pico.getChip}/hardware_regs/${command:raspberry-pi-pico.getChipUppercase}.svd",
|
||||
"runToEntryPoint": "main",
|
||||
// Fix for no_flash binaries, where monitor reset halt doesn't do what is expected
|
||||
// Also works fine for flash binaries
|
||||
"overrideLaunchCommands": [
|
||||
"monitor reset init",
|
||||
"load \"${command:raspberry-pi-pico.launchTargetPath}\""
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
Vendored
+46
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"cmake.showSystemKits": false,
|
||||
"cmake.options.statusBarVisibility": "hidden",
|
||||
"cmake.options.advanced": {
|
||||
"build": {
|
||||
"statusBarVisibility": "hidden"
|
||||
},
|
||||
"launch": {
|
||||
"statusBarVisibility": "hidden"
|
||||
},
|
||||
"debug": {
|
||||
"statusBarVisibility": "hidden"
|
||||
},
|
||||
"variant": {
|
||||
"statusBarVisibility": "hidden"
|
||||
},
|
||||
"buildTarget": {
|
||||
"statusBarVisibility": "hidden"
|
||||
}
|
||||
},
|
||||
"cmake.configureOnEdit": false,
|
||||
"cmake.automaticReconfigure": false,
|
||||
"cmake.configureOnOpen": false,
|
||||
"cmake.generator": "Ninja",
|
||||
"cmake.cmakePath": "${userHome}/.pico-sdk/cmake/v4.3.4/bin/cmake",
|
||||
"C_Cpp.debugShortcut": false,
|
||||
"terminal.integrated.env.windows": {
|
||||
"PICO_SDK_PATH": "${env:USERPROFILE}/.pico-sdk/sdk/2.3.0",
|
||||
"PICO_TOOLCHAIN_PATH": "${env:USERPROFILE}/.pico-sdk/toolchain/15_2_Rel1",
|
||||
"Path": "${env:USERPROFILE}/.pico-sdk/toolchain/15_2_Rel1/bin;${env:USERPROFILE}/.pico-sdk/picotool/2.3.0/picotool;${env:USERPROFILE}/.pico-sdk/cmake/v4.3.4/bin;${env:USERPROFILE}/.pico-sdk/ninja/v1.13.2;${env:PATH}"
|
||||
},
|
||||
"terminal.integrated.env.osx": {
|
||||
"PICO_SDK_PATH": "${env:HOME}/.pico-sdk/sdk/2.3.0",
|
||||
"PICO_TOOLCHAIN_PATH": "${env:HOME}/.pico-sdk/toolchain/15_2_Rel1",
|
||||
"PATH": "${env:HOME}/.pico-sdk/toolchain/15_2_Rel1/bin:${env:HOME}/.pico-sdk/picotool/2.3.0/picotool:${env:HOME}/.pico-sdk/cmake/v4.3.4/bin:${env:HOME}/.pico-sdk/ninja/v1.13.2:${env:PATH}"
|
||||
},
|
||||
"terminal.integrated.env.linux": {
|
||||
"PICO_SDK_PATH": "${env:HOME}/.pico-sdk/sdk/2.3.0",
|
||||
"PICO_TOOLCHAIN_PATH": "${env:HOME}/.pico-sdk/toolchain/15_2_Rel1",
|
||||
"PATH": "${env:HOME}/.pico-sdk/toolchain/15_2_Rel1/bin:${env:HOME}/.pico-sdk/picotool/2.3.0/picotool:${env:HOME}/.pico-sdk/cmake/v4.3.4/bin:${env:HOME}/.pico-sdk/ninja/v1.13.2:${env:PATH}"
|
||||
},
|
||||
"raspberry-pi-pico.cmakeAutoConfigure": true,
|
||||
"raspberry-pi-pico.useCmakeTools": false,
|
||||
"raspberry-pi-pico.cmakePath": "${HOME}/.pico-sdk/cmake/v4.3.4/bin/cmake",
|
||||
"raspberry-pi-pico.ninjaPath": "${HOME}/.pico-sdk/ninja/v1.13.2/ninja"
|
||||
}
|
||||
Vendored
+102
@@ -0,0 +1,102 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "Compile Project",
|
||||
"type": "process",
|
||||
"isBuildCommand": true,
|
||||
"command": "${userHome}/.pico-sdk/ninja/v1.13.2/ninja",
|
||||
"args": ["-C", "${workspaceFolder}/build"],
|
||||
"group": "build",
|
||||
"presentation": {
|
||||
"reveal": "always",
|
||||
"panel": "dedicated"
|
||||
},
|
||||
"problemMatcher": "$gcc",
|
||||
"windows": {
|
||||
"command": "${env:USERPROFILE}/.pico-sdk/ninja/v1.13.2/ninja.exe"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Run Project",
|
||||
"type": "process",
|
||||
"command": "${env:HOME}/.pico-sdk/picotool/2.3.0/picotool/picotool",
|
||||
"args": [
|
||||
"load",
|
||||
"${command:raspberry-pi-pico.launchTargetPath}",
|
||||
"-fx"
|
||||
],
|
||||
"presentation": {
|
||||
"reveal": "always",
|
||||
"panel": "dedicated"
|
||||
},
|
||||
"problemMatcher": [],
|
||||
"windows": {
|
||||
"command": "${env:USERPROFILE}/.pico-sdk/picotool/2.3.0/picotool/picotool.exe"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Flash",
|
||||
"type": "process",
|
||||
"command": "${userHome}/.pico-sdk/openocd/0.12.0+dev/openocd.exe",
|
||||
"args": [
|
||||
"-s",
|
||||
"${userHome}/.pico-sdk/openocd/0.12.0+dev/scripts",
|
||||
"-f",
|
||||
"interface/cmsis-dap.cfg",
|
||||
"-f",
|
||||
"target/${command:raspberry-pi-pico.getTarget}.cfg",
|
||||
"-c",
|
||||
"adapter speed 5000; program \"${command:raspberry-pi-pico.launchTargetPath}\" verify reset exit"
|
||||
],
|
||||
"problemMatcher": [],
|
||||
"windows": {
|
||||
"command": "${env:USERPROFILE}/.pico-sdk/openocd/0.12.0+dev/openocd.exe"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Rescue Reset",
|
||||
"type": "process",
|
||||
"command": "${userHome}/.pico-sdk/openocd/0.12.0+dev/openocd.exe",
|
||||
"args": [
|
||||
"-s",
|
||||
"${userHome}/.pico-sdk/openocd/0.12.0+dev/scripts",
|
||||
"-f",
|
||||
"interface/cmsis-dap.cfg",
|
||||
"-f",
|
||||
"target/${command:raspberry-pi-pico.getChip}-rescue.cfg",
|
||||
"-c",
|
||||
"adapter speed 5000; reset halt; exit"
|
||||
],
|
||||
"problemMatcher": [],
|
||||
"windows": {
|
||||
"command": "${env:USERPROFILE}/.pico-sdk/openocd/0.12.0+dev/openocd.exe"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "RISC-V Reset (RP2350)",
|
||||
"type": "process",
|
||||
"command": "${userHome}/.pico-sdk/openocd/0.12.0+dev/openocd.exe",
|
||||
"args": [
|
||||
"-s",
|
||||
"${userHome}/.pico-sdk/openocd/0.12.0+dev/scripts",
|
||||
"-c",
|
||||
"set USE_CORE { rv0 rv1 cm0 cm1 }",
|
||||
"-f",
|
||||
"interface/cmsis-dap.cfg",
|
||||
"-f",
|
||||
"target/rp2350.cfg",
|
||||
"-c",
|
||||
"adapter speed 5000; init;",
|
||||
"-c",
|
||||
"write_memory 0x40120158 8 { 0x3 }; echo [format \"Info : ARCHSEL 0x%02x\" [read_memory 0x40120158 8 1]];",
|
||||
"-c",
|
||||
"reset halt; targets rp2350.rv0; echo [format \"Info : ARCHSEL_STATUS 0x%02x\" [read_memory 0x4012015C 8 1]]; exit"
|
||||
],
|
||||
"problemMatcher": [],
|
||||
"windows": {
|
||||
"command": "${env:USERPROFILE}/.pico-sdk/openocd/0.12.0+dev/openocd.exe"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#include <stdio.h>
|
||||
#include "pico/stdlib.h"
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
stdio_init_all();
|
||||
|
||||
while (true) {
|
||||
__asm volatile(
|
||||
// Save a low register and the link register.
|
||||
"push {r4, lr}\n"
|
||||
// Intentionally unordered: the encoded list is still r2, r3, r6.
|
||||
"push {r3, r2, r6}\n"
|
||||
// Thumb PUSH cannot encode high registers r8-r12.
|
||||
"stmdb sp!, {r9, r10}\n"
|
||||
// Restore each group in reverse order to return SP to its start.
|
||||
"ldmia sp!, {r9, r10}\n"
|
||||
"pop {r2, r3, r6}\n"
|
||||
"pop {r4, lr}\n"
|
||||
::: "memory");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
# Generated Cmake Pico project file
|
||||
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
# Initialise pico_sdk from installed location
|
||||
# (note this can come from environment, CMake cache etc)
|
||||
|
||||
# == DO NOT EDIT THE FOLLOWING LINES for the Raspberry Pi Pico VS Code Extension to work ==
|
||||
if(WIN32)
|
||||
set(USERHOME $ENV{USERPROFILE})
|
||||
else()
|
||||
set(USERHOME $ENV{HOME})
|
||||
endif()
|
||||
set(sdkVersion 2.3.0)
|
||||
set(toolchainVersion 15_2_Rel1)
|
||||
set(picotoolVersion 2.3.0)
|
||||
set(picoVscode ${USERHOME}/.pico-sdk/cmake/pico-vscode.cmake)
|
||||
if (EXISTS ${picoVscode})
|
||||
include(${picoVscode})
|
||||
endif()
|
||||
# ====================================================================================
|
||||
set(PICO_BOARD pico2 CACHE STRING "Board type")
|
||||
|
||||
# Pull in Raspberry Pi Pico SDK (must be before project)
|
||||
include(pico_sdk_import.cmake)
|
||||
|
||||
project(0x0001a_stack C CXX ASM)
|
||||
|
||||
# Initialise the Raspberry Pi Pico SDK
|
||||
pico_sdk_init()
|
||||
|
||||
# Add executable. Default name is the project name, version 0.1
|
||||
|
||||
add_executable(0x0001a_stack 0x0001a_stack.c )
|
||||
|
||||
pico_set_program_name(0x0001a_stack "0x0001a_stack")
|
||||
pico_set_program_version(0x0001a_stack "0.1")
|
||||
|
||||
# Modify the below lines to enable/disable output over UART/USB
|
||||
pico_enable_stdio_uart(0x0001a_stack 1)
|
||||
pico_enable_stdio_usb(0x0001a_stack 0)
|
||||
|
||||
# Add the standard library to the build
|
||||
target_link_libraries(0x0001a_stack
|
||||
pico_stdlib)
|
||||
|
||||
# Add the standard include files to the build
|
||||
target_include_directories(0x0001a_stack PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
)
|
||||
|
||||
pico_add_extra_outputs(0x0001a_stack)
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
# This is a copy of <PICO_SDK_PATH>/external/pico_sdk_import.cmake
|
||||
|
||||
# This can be dropped into an external project to help locate this SDK
|
||||
# It should be include()ed prior to project()
|
||||
|
||||
# Copyright 2020 (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
# following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
|
||||
# disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products
|
||||
# derived from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH))
|
||||
set(PICO_SDK_PATH $ENV{PICO_SDK_PATH})
|
||||
message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')")
|
||||
endif ()
|
||||
|
||||
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT))
|
||||
set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT})
|
||||
message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')")
|
||||
endif ()
|
||||
|
||||
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH))
|
||||
set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH})
|
||||
message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')")
|
||||
endif ()
|
||||
|
||||
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_TAG} AND (NOT PICO_SDK_FETCH_FROM_GIT_TAG))
|
||||
set(PICO_SDK_FETCH_FROM_GIT_TAG $ENV{PICO_SDK_FETCH_FROM_GIT_TAG})
|
||||
message("Using PICO_SDK_FETCH_FROM_GIT_TAG from environment ('${PICO_SDK_FETCH_FROM_GIT_TAG}')")
|
||||
endif ()
|
||||
|
||||
if (PICO_SDK_FETCH_FROM_GIT AND NOT PICO_SDK_FETCH_FROM_GIT_TAG)
|
||||
set(PICO_SDK_FETCH_FROM_GIT_TAG "master")
|
||||
message("Using master as default value for PICO_SDK_FETCH_FROM_GIT_TAG")
|
||||
endif()
|
||||
|
||||
set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK")
|
||||
set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable")
|
||||
set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK")
|
||||
set(PICO_SDK_FETCH_FROM_GIT_TAG "${PICO_SDK_FETCH_FROM_GIT_TAG}" CACHE FILEPATH "release tag for SDK")
|
||||
|
||||
if (NOT PICO_SDK_PATH)
|
||||
if (PICO_SDK_FETCH_FROM_GIT)
|
||||
include(FetchContent)
|
||||
set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR})
|
||||
if (PICO_SDK_FETCH_FROM_GIT_PATH)
|
||||
get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}")
|
||||
endif ()
|
||||
FetchContent_Declare(
|
||||
pico_sdk
|
||||
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
|
||||
GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG}
|
||||
)
|
||||
|
||||
if (NOT pico_sdk)
|
||||
message("Downloading Raspberry Pi Pico SDK")
|
||||
# GIT_SUBMODULES_RECURSE was added in 3.17
|
||||
if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0")
|
||||
FetchContent_Populate(
|
||||
pico_sdk
|
||||
QUIET
|
||||
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
|
||||
GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG}
|
||||
GIT_SUBMODULES_RECURSE FALSE
|
||||
|
||||
SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src
|
||||
BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build
|
||||
SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild
|
||||
)
|
||||
else ()
|
||||
FetchContent_Populate(
|
||||
pico_sdk
|
||||
QUIET
|
||||
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
|
||||
GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG}
|
||||
|
||||
SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src
|
||||
BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build
|
||||
SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild
|
||||
)
|
||||
endif ()
|
||||
|
||||
set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR})
|
||||
endif ()
|
||||
set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE})
|
||||
else ()
|
||||
message(FATAL_ERROR
|
||||
"SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git."
|
||||
)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
|
||||
if (NOT EXISTS ${PICO_SDK_PATH})
|
||||
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found")
|
||||
endif ()
|
||||
|
||||
set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake)
|
||||
if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE})
|
||||
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK")
|
||||
endif ()
|
||||
|
||||
set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE)
|
||||
|
||||
include(${PICO_SDK_INIT_CMAKE_FILE})
|
||||
@@ -82,6 +82,13 @@ Introduction and Overview of Embedded Reverse Engineering: Ethics, Scoping, and
|
||||
|
||||
### Week 1 Notebook [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK01/WEEK01.md)
|
||||
|
||||
### Week 1a Notebook [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/WEEK01/WEEK01a.md)
|
||||
|
||||
### Chapter 2a: Understanding the ARM Stack
|
||||
This chapter uses OpenOCD and GDB to step through inline Cortex-M33 stack instructions and inspect each saved register in SRAM.
|
||||
|
||||
-> Click [HERE](https://github.com/mytechnotalent/Embedded-Hacking/blob/main/Embedded-Hacking.pdf) to read the FREE pdf book.
|
||||
|
||||
### Chapter 1: hello, world
|
||||
This chapter covers the basics of setting up a dev environment and basic template firmware for the Pico 2 MCU in addition to printing hello, world.
|
||||
|
||||
|
||||
@@ -0,0 +1,511 @@
|
||||
# Week 1a: Understanding the ARM Stack: Inline Assembly and Live Debugging
|
||||
|
||||
***
|
||||
**LEGAL DISCLAIMER:**
|
||||
The information, tools, and code provided in this repository and course are strictly for educational, research, and defensive purposes only.
|
||||
|
||||
You are explicitly prohibited from using any materials contained herein to access, test, modify, or exploit any device, network, or system that you do not own 100% or for which you do not have explicit, documented, and legally binding authorization to interact with.
|
||||
|
||||
By using this repository and course, you acknowledge and agree that:
|
||||
|
||||
1. Any illegal, unauthorized, or malicious use of this information is solely your responsibility.
|
||||
2. The author(s) and contributor(s) of this repository and course shall not be held liable for any damages, legal repercussions, criminal charges, or unauthorized actions resulting from the use, misuse, or abuse of the contents herein.
|
||||
3. You will comply with all applicable local, state, national, and international laws regarding cybersecurity and computer fraud.
|
||||
|
||||
**IF YOU DO NOT AGREE WITH THESE TERMS, DO NOT USE THIS REPOSITORY AND COURSE.**
|
||||
|
||||
***
|
||||
|
||||
## What You'll Learn This Week
|
||||
|
||||
By the end of this week, you will be able to:
|
||||
|
||||
- Understand how the RP2350 Cortex-M33 stack grows in SRAM.
|
||||
- Identify the ARM registers used by this stack experiment.
|
||||
- Build and flash a Pico 2 ELF through a Debug Probe.
|
||||
- Connect OpenOCD and GDB to live hardware.
|
||||
- Step one assembly instruction at a time with `si`.
|
||||
- Examine the exact stack words written by each multi-register instruction.
|
||||
- Prove that an ARM register list is ordered by register number, not source-list spelling.
|
||||
|
||||
---
|
||||
|
||||
## Part 1: Understanding the Basics
|
||||
|
||||
### What is a Microcontroller?
|
||||
|
||||
A microcontroller is a complete small computer on one chip. It contains processor cores, memory controllers, peripherals, and interfaces for hardware such as GPIO, UART, timers, and SPI. The Raspberry Pi Pico 2 uses the **RP2350** microcontroller.
|
||||
|
||||
### What is the ARM Cortex-M33?
|
||||
|
||||
The RP2350 can run Arm Cortex-M33 cores. The program in this folder is built for that Arm target. We will use the Debug Probe, OpenOCD, and GDB to stop a core and inspect its registers and memory while it executes the program.
|
||||
|
||||
### What is Dynamic Analysis?
|
||||
|
||||
Dynamic analysis means observing a program while it runs on real hardware. In this lesson we will:
|
||||
|
||||
- Stop the processor at `main`.
|
||||
- View the instructions produced by the compiler.
|
||||
- Execute one instruction with `si`.
|
||||
- Read the stack pointer and the memory it points to.
|
||||
|
||||
---
|
||||
|
||||
## Part 2: Understanding Processor Registers
|
||||
|
||||
### What is a Register?
|
||||
|
||||
A register is very fast storage inside the CPU. Instructions use registers for values, addresses, temporary results, and control flow.
|
||||
|
||||
### The ARM Cortex-M33 Registers
|
||||
|
||||
| Register | Also Called | Purpose |
|
||||
| --- | --- | --- |
|
||||
| `r0` - `r12` | General purpose | Hold values and addresses while instructions run. |
|
||||
| `r13` | SP | Points to the current top of the stack. |
|
||||
| `r14` | LR | Holds the return address after a function call. |
|
||||
| `r15` | PC | Points to the next instruction to execute. |
|
||||
|
||||
##### General-Purpose Registers (`r0` - `r12`)
|
||||
|
||||
This lesson uses `r2`, `r3`, `r4`, `r6`, `r9`, and `r10`. The assembly saves their current values to SRAM, then restores them before the loop repeats.
|
||||
|
||||
##### The Stack Pointer (`r13` / SP)
|
||||
|
||||
The stack is a region of SRAM used for temporary values, saved registers, return addresses, and local variables. On Cortex-M, the standard stack grows toward lower addresses.
|
||||
|
||||
- A `push` lowers `sp` and writes values below the old stack pointer.
|
||||
- A `pop` reads values at `sp` and raises `sp`.
|
||||
- Each saved register occupies 4 bytes.
|
||||
|
||||
```text
|
||||
Higher addresses
|
||||
+------------------+
|
||||
| Old SP location |
|
||||
+------------------+
|
||||
| Saved value |
|
||||
+------------------+
|
||||
| Saved value | <- SP after a multi-register push
|
||||
+------------------+
|
||||
Lower addresses
|
||||
```
|
||||
|
||||
##### The Link Register (`r14` / LR)
|
||||
|
||||
A `bl` instruction calls a function and stores the return address in `lr`. The compiler-generated prologue for `main` saves `lr` on the stack before calling `stdio_init_all`.
|
||||
|
||||
##### The Program Counter (`r15` / PC)
|
||||
|
||||
The Program Counter identifies the next instruction. In GDB, the `=>` marker in `disas main` points to the instruction that will run when you type `si`.
|
||||
|
||||
---
|
||||
|
||||
## Part 3: Understanding Memory Layout
|
||||
|
||||
### XIP - Execute In Place
|
||||
|
||||
The Pico 2 executes this firmware directly from external flash through XIP. The executable code normally begins at `0x10000000`.
|
||||
|
||||
### Memory Map Overview
|
||||
|
||||
```text
|
||||
+-------------------------------------+
|
||||
| Flash Memory (XIP) |
|
||||
| Starts at: 0x10000000 |
|
||||
| Contains: program instructions |
|
||||
+-------------------------------------+
|
||||
| SRAM |
|
||||
| Starts at: 0x20000000 |
|
||||
| Contains: stack, heap, variables |
|
||||
+-------------------------------------+
|
||||
```
|
||||
|
||||
### Why the Stack Is in SRAM
|
||||
|
||||
The stack changes on every function call and return, so it must be writable. When GDB displays `$sp`, it should show an address in the `0x200...` SRAM range. `x/wx $sp` reads the 32-bit value currently at the top of that stack.
|
||||
|
||||
---
|
||||
|
||||
## Part 3.5: Reviewing Our Stack Code
|
||||
|
||||
The file `0x0001a_stack.c` initializes standard I/O, then repeats this assembly block forever:
|
||||
|
||||
```c
|
||||
__asm volatile(
|
||||
"push {r4, lr}\n"
|
||||
"push {r3, r2, r6}\n"
|
||||
"stmdb sp!, {r9, r10}\n"
|
||||
"ldmia sp!, {r9, r10}\n"
|
||||
"pop {r2, r3, r6}\n"
|
||||
"pop {r4, lr}\n"
|
||||
::: "memory");
|
||||
```
|
||||
|
||||
### Breaking Down the Code
|
||||
|
||||
##### First Push: `push {r4, lr}`
|
||||
|
||||
This lowers `sp` by 8 bytes. At the new stack pointer, the saved values are:
|
||||
|
||||
```text
|
||||
[sp] = r4
|
||||
[sp + 4] = lr
|
||||
```
|
||||
|
||||
##### Second Push: `push {r3, r2, r6}`
|
||||
|
||||
This is deliberately written in a confusing order. The source says `r3` first, but an ARM register list is a set of registers, not an ordered sequence of operations. The assembler encodes the same register mask as `{r2, r3, r6}` and warns that the list is not ascending.
|
||||
|
||||
After one `si`, the stack layout proves the actual rule:
|
||||
|
||||
```text
|
||||
[sp] = r2
|
||||
[sp + 4] = r3
|
||||
[sp + 8] = r6
|
||||
[sp + 12] = r4
|
||||
[sp + 16] = lr
|
||||
```
|
||||
|
||||
The first three words were written by this instruction; `r4` and `lr` remain from
|
||||
the preceding `push {r4, lr}`. The lowest register number in this push is stored
|
||||
at the lowest address. Because the stack grows down, `r6` is closest to the stack
|
||||
pointer value from before this instruction.
|
||||
|
||||
##### High Registers: `stmdb sp!, {r9, r10}`
|
||||
|
||||
The 16-bit Thumb `push` encoding cannot encode high registers `r8` through `r12`.
|
||||
`stmdb sp!` is the general full-descending stack instruction used for `r9` and
|
||||
`r10`.
|
||||
|
||||
```text
|
||||
[sp] = r9
|
||||
[sp + 4] = r10
|
||||
```
|
||||
|
||||
##### The Restore Instructions
|
||||
|
||||
The next instructions restore the same groups in reverse stack-group order. This matters because the last group saved is at the current top of the stack:
|
||||
|
||||
```text
|
||||
ldmia sp!, {r9, r10}
|
||||
pop {r2, r3, r6}
|
||||
pop {r4, lr}
|
||||
```
|
||||
|
||||
The stack pointer ends at the same value it had before the inline assembly, so the infinite loop does not consume stack space.
|
||||
|
||||
### Compiling and Flashing to the Pico 2
|
||||
|
||||
##### Step 1: Compile the Code
|
||||
|
||||
From the project folder, build the program:
|
||||
|
||||
```powershell
|
||||
& "$env:USERPROFILE\.pico-sdk\ninja\v1.13.2\ninja.exe" -C build
|
||||
```
|
||||
|
||||
The expected artifact is `build\0x0001a_stack.elf`. The assembler reports `register range not in ascending order` for the deliberately unordered source list. That warning is expected for this experiment.
|
||||
|
||||
##### Step 2: Flash and Verify
|
||||
|
||||
Use the Debug Probe to flash the ELF and compare target flash with the built image:
|
||||
|
||||
```powershell
|
||||
& "$env:USERPROFILE\.pico-sdk\openocd\0.12.0+dev\openocd.exe" -s "$env:USERPROFILE\.pico-sdk\openocd\0.12.0+dev\scripts" -f interface/cmsis-dap.cfg -f target/rp2350.cfg -c 'adapter speed 5000; targets rp2350.dap.core1; cortex_m reset_config sysresetreq; targets rp2350.dap.core0; program "build/0x0001a_stack.elf" verify reset exit'
|
||||
```
|
||||
|
||||
You should see:
|
||||
|
||||
```text
|
||||
** Programming Finished **
|
||||
** Verify Started **
|
||||
** Verified OK **
|
||||
** Resetting Target **
|
||||
shutdown command invoked
|
||||
```
|
||||
|
||||
`Verified OK` proves that the programmed bytes match the ELF. `shutdown command invoked` is normal because `exit` ends OpenOCD after flashing.
|
||||
|
||||
---
|
||||
|
||||
## Part 4: Dynamic Analysis with GDB
|
||||
|
||||
### Prerequisites
|
||||
|
||||
Before starting, you need:
|
||||
|
||||
1. A Pico 2 with the Debug Probe connected.
|
||||
2. OpenOCD from the installed Pico SDK.
|
||||
3. `arm-none-eabi-gdb`.
|
||||
4. The verified `build\0x0001a_stack.elf` on the Pico 2.
|
||||
|
||||
### Connecting to Your Pico 2 with OpenOCD
|
||||
|
||||
Open a terminal and start the debug server. Leave it running:
|
||||
|
||||
```powershell
|
||||
& "$env:USERPROFILE\.pico-sdk\openocd\0.12.0+dev\openocd.exe" -s "$env:USERPROFILE\.pico-sdk\openocd\0.12.0+dev\scripts" -f interface/cmsis-dap.cfg -f target/rp2350.cfg -c "adapter speed 5000; init"
|
||||
```
|
||||
|
||||
OpenOCD listens for GDB connections on port `3333`.
|
||||
|
||||
##### VM Command
|
||||
|
||||
If the VM has `openocd` on its `PATH`, use the same command without the full executable path:
|
||||
|
||||
```powershell
|
||||
openocd -s "$env:USERPROFILE\.pico-sdk\openocd\0.12.0+dev\scripts" -f interface/cmsis-dap.cfg -f target/rp2350.cfg -c "adapter speed 5000; init"
|
||||
```
|
||||
|
||||
The VM needs USB access to the Debug Probe. Nothing else about the build, ELF, or GDB sequence changes.
|
||||
|
||||
### Connecting to Your Pico 2 with GDB
|
||||
|
||||
Open a second terminal in the project folder:
|
||||
|
||||
```powershell
|
||||
arm-none-eabi-gdb build\0x0001a_stack.elf
|
||||
```
|
||||
|
||||
Connect, reset, halt, and stop at `main`:
|
||||
|
||||
```gdb
|
||||
target extended-remote :3333
|
||||
monitor reset halt
|
||||
b main
|
||||
c
|
||||
disas main
|
||||
```
|
||||
|
||||
You should see this instruction pattern. Your addresses can differ after a rebuild.
|
||||
|
||||
```text
|
||||
=> main: push {r3, lr}
|
||||
main+2: bl stdio_init_all
|
||||
main+6: push {r4, lr}
|
||||
main+8: push {r2, r3, r6}
|
||||
main+10: stmdb sp!, {r9, r10}
|
||||
main+14: ldmia.w sp!, {r9, r10}
|
||||
main+18: pop {r2, r3, r6}
|
||||
main+20: ldmia.w sp!, {r4, lr}
|
||||
main+24: b.n main+6
|
||||
```
|
||||
|
||||
Notice that GDB displays `{r2, r3, r6}`, not the source spelling `{r3, r2, r6}`. That is the encoded register set in canonical order. Depending on the disassembler, register `r10` may be displayed as its conventional alias, `sl`.
|
||||
|
||||
### Basic GDB Commands: Your First Steps
|
||||
|
||||
| Command | Short Form | What It Does |
|
||||
| --- | --- | --- |
|
||||
| `break main` | `b main` | Set a breakpoint at `main`. |
|
||||
| `continue` | `c` | Run until a breakpoint. |
|
||||
| `disassemble` | `disas` | Show the current function's assembly. |
|
||||
| `info registers` | `i r` | Display CPU registers. |
|
||||
| `stepi` | `si` | Execute exactly one instruction. |
|
||||
| `nexti` | `ni` | Execute one instruction without entering a call. |
|
||||
| `x/wx ADDRESS` | | Examine one 32-bit hexadecimal word. |
|
||||
| `monitor reset halt` | | Ask OpenOCD to reset and halt the target. |
|
||||
|
||||
### Watching the Stack Change
|
||||
|
||||
##### Step 1: Inspect the Stack Before the Compiler Prologue
|
||||
|
||||
At the breakpoint, GDB is paused before `push {r3, lr}`. Inspect the current stack pointer and the two words below it:
|
||||
|
||||
```gdb
|
||||
p/x $sp
|
||||
x/2wx $sp-8
|
||||
```
|
||||
|
||||
##### Step 2: Execute One Instruction
|
||||
|
||||
```gdb
|
||||
si
|
||||
```
|
||||
|
||||
The arrow moves to `bl stdio_init_all`. Inspect what the compiler prologue placed on the stack:
|
||||
|
||||
```gdb
|
||||
p/x $sp
|
||||
x/wx $sp
|
||||
x/wx $sp+4
|
||||
```
|
||||
|
||||
The stack pointer moved down 8 bytes. `[sp]` is the saved `r3`; `[sp+4]` is the saved `lr`.
|
||||
|
||||
##### Step 3: Step Over `stdio_init_all`
|
||||
|
||||
Do not step into the library initialization code. Use `ni`:
|
||||
|
||||
```gdb
|
||||
ni
|
||||
disas main
|
||||
```
|
||||
|
||||
The arrow now points at the first inline instruction: `push {r4, lr}`.
|
||||
|
||||
##### Step 4: Prove the First Inline Push
|
||||
|
||||
Read the registers before saving them:
|
||||
|
||||
```gdb
|
||||
p/x $r4
|
||||
p/x $lr
|
||||
p/x $sp
|
||||
```
|
||||
|
||||
Execute one instruction and examine the new top of the stack:
|
||||
|
||||
```gdb
|
||||
si
|
||||
x/wx $sp
|
||||
x/wx $sp+4
|
||||
```
|
||||
|
||||
The values at `[sp]` and `[sp+4]` match the values shown for `r4` and `lr`. This push reduced `sp` by 8 bytes.
|
||||
|
||||
##### Step 5: Prove Register-List Ordering
|
||||
|
||||
Read the three registers before executing the deliberately unordered list:
|
||||
|
||||
```gdb
|
||||
p/x $r2
|
||||
p/x $r3
|
||||
p/x $r6
|
||||
p/x $sp
|
||||
```
|
||||
|
||||
Now execute only that instruction:
|
||||
|
||||
```gdb
|
||||
si
|
||||
x/wx $sp
|
||||
x/wx $sp+4
|
||||
x/wx $sp+8
|
||||
```
|
||||
|
||||
Compare the values from the first three commands with the three words in SRAM:
|
||||
|
||||
```text
|
||||
[sp] matches r2
|
||||
[sp + 4] matches r3
|
||||
[sp + 8] matches r6
|
||||
```
|
||||
|
||||
This is the proof. The source ordered the list as `r3`, `r2`, `r6`, but the stack is laid out by ascending register number. A multi-register push is one CPU instruction, so individual transfers inside that instruction cannot be separately stepped.
|
||||
|
||||
##### Step 6: Prove the High-Register Save
|
||||
|
||||
Read the values and execute one instruction:
|
||||
|
||||
```gdb
|
||||
p/x $r9
|
||||
p/x $r10
|
||||
p/x $sp
|
||||
si
|
||||
x/wx $sp
|
||||
x/wx $sp+4
|
||||
```
|
||||
|
||||
`stmdb sp!, {r9, r10}` moved `sp` down by 8 bytes. The first word equals `r9`; the second equals `r10`.
|
||||
|
||||
##### Step 7: Watch the Restores
|
||||
|
||||
Execute and inspect each restore separately:
|
||||
|
||||
```gdb
|
||||
si
|
||||
p/x $sp
|
||||
x/3wx $sp
|
||||
|
||||
si
|
||||
p/x $sp
|
||||
x/2wx $sp
|
||||
|
||||
si
|
||||
p/x $sp
|
||||
```
|
||||
|
||||
The three instructions raise `sp` by 8, 12, and 8 bytes respectively. The final value is the same stack pointer you saw before the first inline push.
|
||||
|
||||
### Understanding the Stack Diagram
|
||||
|
||||
At the deepest point, after `stmdb sp!, {r9, r10}`, the inline assembly has saved 28 bytes. The `old SP` below is the stack pointer after the separate compiler prologue, not the stack pointer at entry to `main`:
|
||||
|
||||
```text
|
||||
Before inline assembly: At maximum inline stack depth:
|
||||
|
||||
old SP <- SP old SP
|
||||
[old SP - 4] lr
|
||||
[old SP - 8] r4
|
||||
[old SP - 12] r6
|
||||
[old SP - 16] r3
|
||||
[old SP - 20] r2
|
||||
[old SP - 24] r10
|
||||
[old SP - 28] r9 <- SP
|
||||
```
|
||||
|
||||
The restoration sequence removes the top group first: `r9/r10`, then `r2/r3/r6`, then `r4/lr`.
|
||||
|
||||
---
|
||||
|
||||
## Part 5: Summary and Review
|
||||
|
||||
### What We Learned
|
||||
|
||||
1. **Registers**: `sp`, `lr`, and `pc` control stack location, returns, and the next instruction.
|
||||
2. **The stack**: It grows down in SRAM. Pushes decrease `sp`; pops increase it.
|
||||
3. **Multi-register instructions**: Register-list source order is not the stack-memory order. ARM stores lower register numbers at lower addresses.
|
||||
4. **OpenOCD and GDB**: OpenOCD connects to the Debug Probe; GDB connects to OpenOCD on port `3333`.
|
||||
5. **Live evidence**: `si` executes one instruction, and `x/wx $sp` shows the exact 32-bit word that instruction placed at the stack pointer.
|
||||
|
||||
### The Program Flow
|
||||
|
||||
```text
|
||||
+-----------------------------------------------------+
|
||||
| 1. push {r3, lr} |
|
||||
| Compiler saves its prologue registers |
|
||||
+-----------------------------------------------------+
|
||||
| 2. bl stdio_init_all |
|
||||
| Initialize standard I/O |
|
||||
+-----------------------------------------------------+
|
||||
| 3. push {r4, lr} |
|
||||
| Save the first inline group |
|
||||
+-----------------------------------------------------+
|
||||
| 4. push {r3, r2, r6} |
|
||||
| Source order differs from stack-memory order |
|
||||
+-----------------------------------------------------+
|
||||
| 5. stmdb / ldmia / pop / pop |
|
||||
| Save and restore all groups |
|
||||
+-----------------------------------------------------+
|
||||
| 6. b.n main+6 |
|
||||
| Repeat with the original stack pointer |
|
||||
+-----------------------------------------------------+
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Key Takeaways
|
||||
|
||||
1. **The stack grows downward**: a push decreases the numeric value in `sp`.
|
||||
2. **A register list is not a sequence**: `{r3, r2, r6}` and `{r2, r3, r6}` encode the same register set.
|
||||
3. **Memory is the proof**: after `si`, inspect `[sp]`, `[sp+4]`, and `[sp+8]` with GDB.
|
||||
4. **The restore order matters**: always restore the most recently saved group first.
|
||||
5. **Balanced stack operations are required**: the loop returns `sp` to its starting value on every iteration.
|
||||
|
||||
---
|
||||
|
||||
## Glossary
|
||||
|
||||
| Term | Definition |
|
||||
| --- | --- |
|
||||
| **Assembly** | Human-readable form of processor instructions. |
|
||||
| **Breakpoint** | A debugger stop point. |
|
||||
| **Debug Probe** | Hardware interface that lets OpenOCD communicate with the target over SWD. |
|
||||
| **GDB** | GNU Debugger, used to inspect and control the running target. |
|
||||
| **LR** | Link Register, holding a function return address. |
|
||||
| **OpenOCD** | Debug server that bridges GDB and the Debug Probe. |
|
||||
| **PC** | Program Counter, pointing to the next instruction. |
|
||||
| **SP** | Stack Pointer, pointing to the top of the stack. |
|
||||
| **SRAM** | Writable memory used for runtime data and the stack. |
|
||||
| **XIP** | Execute In Place, executing program code directly from flash. |
|
||||
Binary file not shown.
Reference in New Issue
Block a user