<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Can Gulmez</title>
    <description>The latest articles on DEV Community by Can Gulmez (@cangulmez).</description>
    <link>https://dev.to/cangulmez</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3457100%2F58231770-b49c-45be-a12c-22330682820e.png</url>
      <title>DEV Community: Can Gulmez</title>
      <link>https://dev.to/cangulmez</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cangulmez"/>
    <language>en</language>
    <item>
      <title>An introduction to ARM Cortex-M3/4</title>
      <dc:creator>Can Gulmez</dc:creator>
      <pubDate>Fri, 17 Jul 2026 16:00:39 +0000</pubDate>
      <link>https://dev.to/cangulmez/an-introduction-to-arm-cortex-m34-a46</link>
      <guid>https://dev.to/cangulmez/an-introduction-to-arm-cortex-m34-a46</guid>
      <description>&lt;p&gt;Another tutorial series on writing a RTOS kernel...&lt;/p&gt;

&lt;p&gt;I'm starting a new series about writing a RTOS kernel for ARM Cortex-M3/4 processors which are the base choices for commonly used STM32, NXP microcontrollers. I plan giving the all theoretical and practical details so that you guys will have the skills that most engineer don't have.&lt;/p&gt;

&lt;p&gt;Firstly, let me give the my notes on the processors itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;

&lt;p&gt;The Cortex-M3 and Cortex-M4 processors are ARMv7-M architecture.&lt;/p&gt;

&lt;h3&gt;
  
  
  Programmer's Model
&lt;/h3&gt;

&lt;p&gt;Both processors have two operation status and two modes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Handler mode: When executing an exception handler such as ISR. When in handler mode, the processor always has privileged access level.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Thread mode: When executing normal application code, the processor can be either in privileged access level or unprivileged level. This is controlled by a special register called &lt;em&gt;CONTROL&lt;/em&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Software can switch the processor in privileged thread mode to unprivileged thread mode. However, it cannot switch itself back from unprivileged to privileged.&lt;/p&gt;

&lt;h4&gt;
  
  
  Registers
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fah8tnli2jq1jv7fns0ck.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fah8tnli2jq1jv7fns0ck.png" alt=" " width="499" height="508"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Registers &lt;em&gt;R0-R12&lt;/em&gt; are general purpose registers. The first eight (&lt;em&gt;R0-R7&lt;/em&gt;) are also called low registers. Due to the limited available space in the instruction set, many 16-bit instructions can only access the low registers. The higher registers (&lt;em&gt;R8-R12&lt;/em&gt;) can be used with 32-bit instructions, and a few with 16-bit instruction. The initial values of &lt;em&gt;R0-R12&lt;/em&gt; are undefined.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R13, Stack Pointer (SP)&lt;/em&gt; is used for accessing the stack memory via &lt;em&gt;PUSH&lt;/em&gt; and &lt;em&gt;POP&lt;/em&gt; operations. Physically there are two different: &lt;em&gt;Main Stack Pointer (MSP)&lt;/em&gt; and &lt;em&gt;Process Stack Pointer (PSP).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The selection of &lt;em&gt;SP&lt;/em&gt; is determined by a special register called &lt;em&gt;CONTROL&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;For most cases, it is not necessary to use the &lt;em&gt;PSP&lt;/em&gt; if the application doesn't require an embedded OS. Many simple applications can rely on the &lt;em&gt;MSP&lt;/em&gt; completely. The &lt;em&gt;PSP&lt;/em&gt; is normally used when an embedded OS is involved, where the stack for the OS kernel and application tasks are separated. The initial value of &lt;em&gt;PSP&lt;/em&gt; is undefined, and the initial of &lt;em&gt;MSP&lt;/em&gt; is taken from the first word of the memory during the reset sequence.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R14, Link Register (LR)&lt;/em&gt; is used for holding the return address when calling a function or subroutine. During exception handling, the LR is also updated automatically to a special &lt;em&gt;EXC_RETURN&lt;/em&gt; value, which is then used for triggering the exception return  at the end of the exception handler.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R15, Program Counter (PC)&lt;/em&gt; returns the current instruction address plus 4 (this is due to the pipeline nature of the design).&lt;/p&gt;

&lt;h3&gt;
  
  
  Behavior of the Application Program Status Register
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl0wc1juc8reo16u93q0o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl0wc1juc8reo16u93q0o.png" alt=" " width="421" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;Program Status Register&lt;/em&gt; is composed of three status registers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Application PSR (APSR)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Execution PSR (EPSR)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Interrupt PSR (IPSR)&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These three registers can be accessed as one combined register, referred to as &lt;em&gt;xPSR&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;PRIMASK&lt;/em&gt;, &lt;em&gt;FAULTMASK&lt;/em&gt;, and &lt;em&gt;BASEPRI&lt;/em&gt; registers are all used for exception or interrupt masking. Each exception has a priority level where a smaller number is a higher priority. These special registers are used to mask exceptions based on priority levels.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;PRIMASK&lt;/em&gt; register is a 1-bit wide interrupt mask register. When set, it blocks all exceptions apart from the &lt;em&gt;NMI&lt;/em&gt; and &lt;em&gt;HardFault&lt;/em&gt; exception. The most common usage is to disable all interrupts for a time critical process. The &lt;em&gt;FAULTMASK&lt;/em&gt; register is very similar to &lt;em&gt;PRIMASK&lt;/em&gt;, but it also blocks the &lt;em&gt;HardFault&lt;/em&gt; exception. Unlike &lt;em&gt;PRIMASK&lt;/em&gt;, &lt;em&gt;FAULTMASK&lt;/em&gt; is cleared automatically at exception return. The &lt;em&gt;BASEPRI&lt;/em&gt; makes exceptions or interrupts based on priority level. When &lt;em&gt;BASEPRI&lt;/em&gt; is set to 0, it is disabled. When it is set to a non-zero value, it blocks exceptions (including interrupts) that have the same or lower priority level., while allowing exceptions with a higher priority level to be accepted by the processor.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;CONTROL&lt;/em&gt; register defines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The selection of stack pointer (&lt;em&gt;MSP&lt;/em&gt; or &lt;em&gt;PSP&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;Access level in thread mode (privileged/unprivileged)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In addition, for Cortex-M4 processor with a floating point unit, one bit of the &lt;em&gt;CONTROL&lt;/em&gt; register indicates if the current context uses the floating point unit or not.&lt;/p&gt;

&lt;p&gt;The Cortex-M4 processor has an optional floating-point unit. This provides additional registers for floating-point data processing, as well as a &lt;em&gt;Floating Point Status and Control Register (FPSCR)&lt;/em&gt;. &lt;em&gt;S0-S32&lt;/em&gt; ("S" means single precision) and &lt;em&gt;D0-D15&lt;/em&gt; ("D" means double precision) can be accessed using floating-point instructions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Memory System
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fssq8cabx4m9cxdf3rtzh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fssq8cabx4m9cxdf3rtzh.png" alt=" " width="617" height="339"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Cortex-M3/4 processors have the following memory system features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;4GB linear address space with 32-bit addressing.&lt;/li&gt;
&lt;li&gt;Architecturally defined memory map - the 4GB memory space is divided into a number of regions for various predefined and peripheral uses.&lt;/li&gt;
&lt;li&gt;Support for little- and big-endian memory systems.&lt;/li&gt;
&lt;li&gt;Bit band accesses - this allows atomic access to individual bits in SRAM or peripheral address space.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Memory Protection Unit (MPU)&lt;/em&gt; - The &lt;em&gt;MPU&lt;/em&gt; is a programmable unit which defines access permissions for various memory regions.&lt;/li&gt;
&lt;li&gt;Unaligned transfer support&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;em&gt;MPU&lt;/em&gt; can be used to protect memory regions by means of defining access permissions in privileged and unprivileged access states.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exception and Interrupt
&lt;/h3&gt;

&lt;p&gt;Exceptions are events that cause changes to program flow. When one happens, the processor suspends the current execution task and executes a part of the program called the exception handler. After the execution of the exception handler is completed, the processor then resumes normal program execution. Interrupts are one type of exception and generally are generated from peripheral or external inputs, and in some cases they can be triggered by software. The exception handlers for interrupts are also referred to as Interrupt Service Routines (ISRes).&lt;/p&gt;

&lt;p&gt;Each exception source has an exception number. Exception numbers 1 to 15 are classified as system exceptions, and exceptions 16 and above are for interrupts.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;NVIC (Nested Vectored Interrupt Controller)&lt;/em&gt; handles the exceptions and interrupt configurations, prioritization, and interrupt masking. The &lt;em&gt;NVIC&lt;/em&gt; has the following features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Flexible exception and interrupt management&lt;/li&gt;
&lt;li&gt;Nested exception/interrupt support&lt;/li&gt;
&lt;li&gt;Vectored exception/interrupt entry&lt;/li&gt;
&lt;li&gt;Interrupt masking&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When an exception event tasks place and is accepted by the processor code, the corresponding exception handler is executed. To determine the starting address of the exception handler, a vector table mechanism is used. The vector table is an array of word data inside the system memory, each representing the starting address of one exception type.&lt;/p&gt;

&lt;p&gt;Several types of exceptions are fault handling exceptions. By default the &lt;em&gt;BusFault&lt;/em&gt;, &lt;em&gt;UsageFault&lt;/em&gt;, and &lt;em&gt;MemManageFault&lt;/em&gt; are disabled and all fault events trigger the &lt;em&gt;HardFault&lt;/em&gt; exceptions. However, the configurations are programmable and you can enable the three programmable fault exceptions individually to handle different types of faults. The &lt;em&gt;HardFault&lt;/em&gt; exception is always enabled.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;System Control Block (SCB)&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;The SCB contains various registers for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Controlling processor configurations (e.g., low-power mode)&lt;/li&gt;
&lt;li&gt;Providing fault status information (fault status registers)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Vector Table Relocation (VTOR)&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Debug
&lt;/h3&gt;

&lt;p&gt;There are two types of interfaces provided in the Cortex-M processors: debug and trace. The debug interface allows a  debug adaptor to connect to a Cortex-M microcontroller to control the debug features and access the memory space on the chip. The Cortex-M processor supports both &lt;em&gt;JTAG&lt;/em&gt; and &lt;em&gt;SWD&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The trace interface is used to collect information from the processor during run-time such as data, event, profiling information, or even complete details of program execution.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reset and Reset Sequence
&lt;/h3&gt;

&lt;p&gt;In typical Cortex-M microcontrollers, there can be three types of reset:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Power on reset - reset everything in the microcontroller. This includes the processor and its debug support component and peripherals.&lt;/li&gt;
&lt;li&gt;System reset - reset just the processor and peripherals, but not the debug support component of the processor.&lt;/li&gt;
&lt;li&gt;Processor reset - reset the processor only.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After reset and before the processor starts executing the program, the Cortex-M processors read the first two words from the memory. The beginning of the memory space contains the vector table, and the first two words in the vector table are the initial value for MSP.&lt;/p&gt;

&lt;h2&gt;
  
  
  Instruction Set
&lt;/h2&gt;

&lt;p&gt;The &lt;em&gt;SuperVisor Call (SVC)&lt;/em&gt; instruction is used to generate the SVC exception. Typically, &lt;em&gt;SVC&lt;/em&gt; is used with an embedded RTOS, where an application task running in an unprivileged execution state can request services from the OS, which runs in the privileged execution state. The &lt;em&gt;SVC&lt;/em&gt; exception mechanism provides the transition from unprivileged to privileged.&lt;/p&gt;

&lt;p&gt;The switching of &lt;em&gt;PRIMASK&lt;/em&gt; or &lt;em&gt;FAULTMASK&lt;/em&gt; to disable and enable an interrupt is commonly used to ensure timing critical code can finish quickly without getting interrupted.&lt;/p&gt;

&lt;p&gt;There are two main instructions for entering sleep modes: &lt;em&gt;Wait for Interrupt (WFI)&lt;/em&gt; and &lt;em&gt;Wait for Event (WFE)&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Memory barrier instructions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;DMB (Data Memory Barrier)&lt;/em&gt;; ensures that all memory accesses are completed before new memory access is committed.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;DSB (Data Synchronization Barrier)&lt;/em&gt;; ensures that all memory accesses are completed before next instruction is executed.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;ISB (Instruction Synchronization Barrier)&lt;/em&gt;; flushes the pipeline and ensures that all previous instructions are completed before executing new instructions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Exception and Interrupts
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs4mxzpfuo4sa3r6sx42v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs4mxzpfuo4sa3r6sx42v.png" alt=" " width="611" height="312"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When the Cortex-M processor accepts an exception request, the processor needs to determine  the starting address of the exception handler. This information is stored in the vector table in the memory. By default, the vector table starts at memory address 0, and the vector address is arranged according to the exception number times. The vector table is normally defined in the startup codes provided by vendors.&lt;/p&gt;

&lt;p&gt;The vector table used in startup code also contains the initial value of the main stack pointer (&lt;em&gt;MSP&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;There are various status attributes applicable to each interrupt:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each interrupt can be either disabled or enabled&lt;/li&gt;
&lt;li&gt;Each interrupt can be either pending or not pending&lt;/li&gt;
&lt;li&gt;Each interrupt can be either in active or inactive state&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The processor accepts an exception if the following &lt;br&gt;
conditions are met:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The processor is running&lt;/li&gt;
&lt;li&gt;The exception is enabled&lt;/li&gt;
&lt;li&gt;The exception has higher priority than the current priority level&lt;/li&gt;
&lt;li&gt;The exception is not blocked by an exception masking register&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An exception entrance sequence contains several operations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stacking of a number of registers.&lt;/li&gt;
&lt;li&gt;Fetching the exception vector.&lt;/li&gt;
&lt;li&gt;Fetching the instructions in parallel to the stacking operation to reduce latency.&lt;/li&gt;
&lt;li&gt;Fetching the instructions for the exception handler to be executed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Exception Handling in Detail
&lt;/h2&gt;

&lt;p&gt;You can program your exception handlers or ISR as normal C routines/functions.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R0-R3&lt;/em&gt;, &lt;em&gt;R12&lt;/em&gt;, &lt;em&gt;LR&lt;/em&gt;, and &lt;em&gt;PSR&lt;/em&gt; are called "caller saved registers". The program code that calls a subroutine needs to save these register contents into memory before the function call if these values will still be needed after the function call. Register values that are not required after the function call don't have to be saved.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R4-R11&lt;/em&gt; are called "callee-saved registers". The subroutine or function being called needs to make sure the contents of these registers are unaltered at the end of the function. The values of these registers could change in the middle of the function execution, but need to be restored to their original values before function exit.&lt;/p&gt;

&lt;p&gt;In order to allow a C function to be used as an exception handler, the exception mechanism needs to save &lt;em&gt;R0-R3&lt;/em&gt;, &lt;em&gt;R12&lt;/em&gt;, &lt;em&gt;LR&lt;/em&gt;, and &lt;em&gt;PSR&lt;/em&gt; at exception entrance automatically, and restore them at exception exit under the control of the processor's hardware.&lt;/p&gt;

&lt;p&gt;So in total eight registers need to be saved during the&lt;br&gt;
exception handling sequence. For the Cortex-M4 processor with  floating-point unit, the exception mechanism also needs to save &lt;em&gt;S0-S15&lt;/em&gt; and &lt;em&gt;FPSCR&lt;/em&gt; if the floating-point unit is used. This  is indicated by a bit in the &lt;em&gt;CONTROL&lt;/em&gt; register called &lt;em&gt;FPCA&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;As the processor enters the execution handler or Interrupt Service Routine (ISR), the value of the LR is updated to code called &lt;em&gt;EXC_RETURN&lt;/em&gt;. The value of this code is used to trigger the exception return mechanism when it is loaded into the PC.&lt;/p&gt;

&lt;p&gt;When an exception occurs and is accepted by the processor, the stacking sequence starts to push the registers into the stack, forming the stack frame.&lt;/p&gt;

&lt;p&gt;The term 'interrupt latency' refers to the delay from the start of the interrupt request to the start of the interrupt handler execution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Low Power and System Control Features
&lt;/h2&gt;

&lt;p&gt;Today we see many low power Cortex-M microcontrollers with very sophisticated system features that enable longer battery life. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Various run modes and sleep modes are available&lt;/li&gt;
&lt;li&gt;Ultra low power &lt;em&gt;Real-Time Clock (RTC)&lt;/em&gt;, watchdog and &lt;em&gt;Brown-Out Detector (BOD)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Smart peripherals that can operate while the processor remains in sleep mode&lt;/li&gt;
&lt;li&gt;Flexible clock system control features to allow clock signals for inactive parts of the design to be turned off&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The processor support two sleep modes: Sleep and Deep Sleep. The Cortex-M processor provides a register called the &lt;em&gt;System Control Register (SCR)&lt;/em&gt; to allow you to select between the Sleep mode and Deep Sleep mode.&lt;/p&gt;

&lt;p&gt;The processor provides two instructions for entering sleep modes: &lt;em&gt;WFI&lt;/em&gt; and &lt;em&gt;WFE&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;WFE&lt;/em&gt; can be woken up by any events. This event register can be set by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Exception entrance and exit&lt;/li&gt;
&lt;li&gt;When &lt;em&gt;SEV-On-Pend&lt;/em&gt; feature is enabled&lt;/li&gt;
&lt;li&gt;An &lt;em&gt;External Event Signal (RXEV)&lt;/em&gt; from on-ship hardware&lt;/li&gt;
&lt;li&gt;Execution of the &lt;em&gt;SEV (Send Event)&lt;/em&gt; instruction&lt;/li&gt;
&lt;li&gt;Debug event&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;em&gt;Sleep-on-Exit&lt;/em&gt; feature is very useful for interrupt driven applications where all operations are carried out inside the interrupt handler. When enabled, the Cortex-M processor automatically enters sleep mode when exiting from an exception handler and returning to thread mode.&lt;/p&gt;

&lt;p&gt;The Cortex-M processors have a small integrated timer called the &lt;em&gt;SysTick&lt;/em&gt; timer. It is integrated as a part of the &lt;em&gt;NVIC&lt;/em&gt; and can generate the &lt;em&gt;SysTick&lt;/em&gt; exception. The &lt;em&gt;SysTick&lt;/em&gt; timer is a simple decrement 24-bit timer, and can run on processor clock frequency or from a reference clock frequency.&lt;/p&gt;

&lt;h2&gt;
  
  
  OS Support Features
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv82qndib3tlb90x4t2zd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv82qndib3tlb90x4t2zd.png" alt=" " width="599" height="372"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A number of features are implemented in the architecture to make OS implementation easier and more efficient. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Shadowed stack pointer: Two stack pointers are available. The &lt;em&gt;MSP&lt;/em&gt; is used for the OS kernel and interrupt handlers. The &lt;em&gt;PSP&lt;/em&gt; is used by application tasks.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;SysTick&lt;/em&gt; timer: A simple timer included inside the processor. This enables an embedded OS to be used on the wide range of Cortex-M microcontrollers available.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;SVC&lt;/em&gt; and &lt;em&gt;PendSV&lt;/em&gt; exceptions: These two exception types are essential for the operations of embedded OSs such as the implementation of context switching.&lt;/li&gt;
&lt;li&gt;Unprivileged execution level: This allows a basic security model that restricts the access rights of some application tasks.&lt;/li&gt;
&lt;li&gt;Exclusive accesses: The exclusive load and store instructions are useful for semaphore and mutual exclusive operations in the OS.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;MSP is the default stack pointer. It is used in the thread mode when the &lt;em&gt;CONTROL&lt;/em&gt; bit&lt;a href="https://dev.toSPSEL"&gt;1&lt;/a&gt; is 0, and it is always used in handler mode.&lt;/p&gt;

&lt;p&gt;PSP is used in thread mode when the &lt;em&gt;CONTROL&lt;/em&gt; bit &lt;a href="https://dev.toSPSEL"&gt;1&lt;/a&gt; is set to 1.&lt;/p&gt;

&lt;p&gt;Stack operations like PUSH and POP instructions, and most instructions that use SP use the currently selected stack pointer. You can also access the &lt;em&gt;MSP&lt;/em&gt; and &lt;em&gt;PSP&lt;/em&gt; directly using &lt;em&gt;MRS&lt;/em&gt; and &lt;em&gt;MSR&lt;/em&gt; instructions. In simple applications without an embedded OS or RTOS, you can just use the &lt;em&gt;MSP&lt;/em&gt; for all operations and ignore the &lt;em&gt;PSP&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;In system with an embedded OS or RTOS, the exception handlers use the &lt;em&gt;MSP&lt;/em&gt;, while application tasks use the &lt;em&gt;PSP&lt;/em&gt;. Each application task has its own stack space, and the context-switching code in the OS updates the &lt;em&gt;PSP&lt;/em&gt; each time the context is switched.&lt;/p&gt;

&lt;p&gt;Typically, to use the process stack, put OS in handler mode, and program &lt;em&gt;PSP&lt;/em&gt; directly, then use an exception return sequence to "jump" into the application task.&lt;/p&gt;

&lt;p&gt;For example, when an OS first starts in thread mode, it can use the &lt;em&gt;SVC&lt;/em&gt; exception to enter the handler mode. Then it can create a stack frame in the process stack, and trigger an exception return that uses the &lt;em&gt;PSP&lt;/em&gt;. When the stack frame is loaded, the application is started.&lt;/p&gt;

&lt;p&gt;In OS designs, we need to switch between different tasks. This is typically called context-switching. Context-switching is usually carried out in the &lt;em&gt;PendSV&lt;/em&gt; exception handler, which can triggered by the periodic &lt;em&gt;SysTick&lt;/em&gt; exception. Inside the context-switching operation, we need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Save the current status of the registers in the current task&lt;/li&gt;
&lt;li&gt;Save the current &lt;em&gt;PSP&lt;/em&gt; value&lt;/li&gt;
&lt;li&gt;Set the &lt;em&gt;PSP&lt;/em&gt; to the last SP value for the next task&lt;/li&gt;
&lt;li&gt;Restore the last values for the next tasks&lt;/li&gt;
&lt;li&gt;Use exception return to switch to the task&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;em&gt;SVC&lt;/em&gt; exception is generated using the &lt;em&gt;SVC&lt;/em&gt; instruction. An immediate value is required for this instruction, which works as a parameter-passing method. The &lt;em&gt;SVC&lt;/em&gt; exception handler can then extract the parameter and determine what action it needs to perform. For example:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SVC   #0x3    ; Call SVC function 3&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;PendSV&lt;/em&gt; exception is triggered by setting its pending status by writing to the &lt;em&gt;Interrupt Control and State Register (ICSR)&lt;/em&gt;. Unlike the &lt;em&gt;SVC&lt;/em&gt; exception, it is not precise. So its pending status can be set inside a higher priority exception handler and executed when the higher-priority handler finishes. Using this case, we can schedule the &lt;em&gt;PendSV&lt;/em&gt; exception handler to be executed after all other interrupt processing tasks are done, by making sure that the &lt;em&gt;PendSV&lt;/em&gt; has the lowest exception priority level. This is very useful for a context switching operation, which is key operation in various OS designs.&lt;/p&gt;

&lt;p&gt;Below shows an example sequence of context-switching using &lt;em&gt;PendSV&lt;/em&gt; with the following event sequence:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Task A calls &lt;em&gt;SVC&lt;/em&gt; for task switching.&lt;/li&gt;
&lt;li&gt;The OS receives the request, prepares for context switching, and pends the &lt;em&gt;PendSV&lt;/em&gt; exception.&lt;/li&gt;
&lt;li&gt;When the CPU exits &lt;em&gt;SVC&lt;/em&gt;, it enters &lt;em&gt;PendSV&lt;/em&gt; immediately and does the context switch.&lt;/li&gt;
&lt;li&gt;When &lt;em&gt;PendSV&lt;/em&gt; finishes and returns to thread level, it executes Task B.&lt;/li&gt;
&lt;li&gt;An interrupt occurs and interrupt handler is entered.&lt;/li&gt;
&lt;li&gt;While running the interrupt handler routine, a &lt;em&gt;SysTick&lt;/em&gt; exception takes place.&lt;/li&gt;
&lt;li&gt;The OS carries out the essential operation, then pends the &lt;em&gt;PendSV&lt;/em&gt; exception and gets ready for the context switch.&lt;/li&gt;
&lt;li&gt;When the &lt;em&gt;SysTick&lt;/em&gt; exception exits, it returns to the interrupt service routine.&lt;/li&gt;
&lt;li&gt;When the interrupt service routine completes, the &lt;em&gt;PendSV&lt;/em&gt; starts and does the actual context-switch operations.&lt;/li&gt;
&lt;li&gt;When &lt;em&gt;PendSV&lt;/em&gt; is complete, the program returns to thread level; this time it returns to task A and continues the processing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In a multi-tasking system, it is common that a number of tasks need to share a limited number of resources. This feature is usually called a semaphore. For the case when only one resource is available, it is also called mutual exclusive, which is one type of semaphore.&lt;/p&gt;

&lt;p&gt;The processor supports a feature called exclusive access. The semaphore variable are read and written using exclusive load and exclusive store.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fault Exceptions and Fault Handling
&lt;/h2&gt;

&lt;p&gt;By default, all the faults trigger the &lt;em&gt;HardFault&lt;/em&gt; exception. Cortex-M3/4 processors have three additional configurable fault exception handlers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;MemManageFault&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;BasFault&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;UsageFault&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These exceptions are triggered if they are enabled, and if their priority is higher than the current exception priority level. These exceptions are called 'configurable fault' exceptions, and have programmable exception priority levels.&lt;/p&gt;

&lt;p&gt;The fault handlers can be used in a number of ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Shut down the system safely&lt;/li&gt;
&lt;li&gt;Inform users or other systems that it encountered a problem&lt;/li&gt;
&lt;li&gt;Carry out self-reset&lt;/li&gt;
&lt;li&gt;In the case of multi-tasking systems, the offending tasks could be terminated and restarted&lt;/li&gt;
&lt;li&gt;Other remedial actions can be carried out o try to fix the problem if possible&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The help detect what type of error was encountered in the fault handler, the Cortex-M3/4 processors also have a number of &lt;em&gt;Fault Status Registers (FSRs)&lt;/em&gt;. The status bits inside these FSRs indicate the kind of fault detected.&lt;/p&gt;

&lt;p&gt;Causes of faults:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Memory management faults&lt;/li&gt;
&lt;li&gt;Bus faults&lt;/li&gt;
&lt;li&gt;Usage faults&lt;/li&gt;
&lt;li&gt;Hard Faults&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Floating-Point Operations
&lt;/h2&gt;

&lt;p&gt;The &lt;em&gt;Floating Point Unit (FPU)&lt;/em&gt; in the Cortex-M4 processor is optional and supports single precision floating point &lt;br&gt;
calculations. The &lt;em&gt;FPU&lt;/em&gt; in the Cortex-M4 processor is based on an extension of the ARMv7-M architecture called &lt;em&gt;FPv4-SP&lt;/em&gt; (Floating Point version 4 - Single Precision). This is a  subset of the &lt;em&gt;VFPv4-D16&lt;/em&gt; extension for ARMv-7A and ARMv7-R architecture.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;FPU&lt;/em&gt; adds a number of registers to the processor system:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;CPACR (Co-processor Access Control Register)&lt;/em&gt; in &lt;em&gt;SCB (System Control Block)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Floating point register bank&lt;/li&gt;
&lt;li&gt;Floating point &lt;em&gt;Status and Control Register (FPSCR)&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Introduction to the Debug and Trace Features
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9bizoqn08drxby68bdr8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9bizoqn08drxby68bdr8.png" alt=" " width="610" height="198"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Two types of trace interface operation modes are supported: either a single-pin model called &lt;em&gt;Serial Wire Viewer (SWV)&lt;/em&gt; (using a signal called &lt;em&gt;Serial Wire Output (SWO)&lt;/em&gt;), or multi-pin &lt;em&gt;Trace Port&lt;/em&gt; interface.&lt;/p&gt;

&lt;p&gt;The debug and trace features of the Cortex-M processors are designed based on the &lt;em&gt;CoreSight Debug&lt;/em&gt; architecture.&lt;/p&gt;

&lt;p&gt;Many Cortex-M microcontrollers support both &lt;em&gt;JTAG&lt;/em&gt; and &lt;em&gt;SWD&lt;/em&gt;  protocols.&lt;/p&gt;

&lt;p&gt;Another part of the &lt;em&gt;CoreSight&lt;/em&gt; architecture concerns trace data handling. In the Cortex-M3/4 processors, there can be three types of trace source:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Embedded Trace Macrocell (ETM)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Data Watchpoint and Trace (DWT)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Instrumentation Trace Macrocell (ITM)&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I think that I've noted the all required details to start writing the RTOS kernel. In next post, I will start writing it.&lt;/p&gt;

&lt;p&gt;Resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Definitive Guide to ARM Cortex-M3 and ARM Cortex-M4 Processors, Third Edition, Joseph Yiu, Newnes, 2014
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>c</category>
      <category>lowcode</category>
      <category>computerscience</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Embedded Linux Development - Part 6</title>
      <dc:creator>Can Gulmez</dc:creator>
      <pubDate>Tue, 21 Apr 2026 09:03:18 +0000</pubDate>
      <link>https://dev.to/cangulmez/embedded-linux-development-part-6-122k</link>
      <guid>https://dev.to/cangulmez/embedded-linux-development-part-6-122k</guid>
      <description>&lt;p&gt;In this tutorial, I will continue to discuss embedded Linux development with &lt;em&gt;ssh&lt;/em&gt; server activation. Previously, I've entered into BeagleBone Black over J1 serial header with a USB-UART converter. In here, I will show that how to enter into it with ssh command.&lt;/p&gt;

&lt;p&gt;Firstly, there are two important points that you have to do. I've already did these in previous tutorials. Firstly, I compiled the kernel with &lt;em&gt;USB Gadget&lt;/em&gt; module and secondly, I installed &lt;em&gt;openssh-server&lt;/em&gt; package into the rootfs. USB gadget module enables the USB connection as the virtual ethernet adapter.&lt;/p&gt;

&lt;p&gt;Let's do required settings for both side. Use the J1 serial header again to enter into the BeagleBone Black.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fosfzwghyeth0o8qm9j16.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fosfzwghyeth0o8qm9j16.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Type the "root" and the your password (set in previous tutorial). Also creating a normal user is good practice.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root@can:/# useradd &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; /bin/bash can
root@can:/# passwd can
root@can:/# usermod &lt;span class="nt"&gt;-aG&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;can
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've created a user named "can" and set the its password. After that go to the your home directory and create a bash script. I named it as &lt;em&gt;setup-usb-gadget.sh&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;root@can:/home/can#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ls&lt;/span&gt;
&lt;span class="go"&gt;setup-usb-gadget.sh
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open and copy this into that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="nv"&gt;INTERFACE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"usb0"&lt;/span&gt;
&lt;span class="nv"&gt;IP_ADDR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"198.168.7.2/24"&lt;/span&gt;

&lt;span class="c"&gt;# Load the g_ether kernel module that creates the ethernet virtual link.&lt;/span&gt;
modprobe g_ether

&lt;span class="c"&gt;# Configure the link interface.&lt;/span&gt;
ip addr flush dev &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$INTERFACE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
ip &lt;span class="nb"&gt;link set&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$INTERFACE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; up
ip addr add &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$IP_ADDR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; dev &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$INTERFACE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# Ensure that SSH is running.&lt;/span&gt;
systemctl start ssh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In here, I loaded the &lt;em&gt;g_ether&lt;/em&gt; module into the kernel. It's the name of USB gadget module. It will create &lt;em&gt;usb0&lt;/em&gt; interface. After that I set it as "up" and its IP address as "198.168.7.2". You can give any IP address, doesn't matter. But generally, "198.168.7.2" is used. Lastly make sure that ssh server is enabled.&lt;/p&gt;

&lt;p&gt;Set the executable permission:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;root@can:/home/can#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x ./setup-usb-gadget.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then run it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;root@can:/home/can#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./setup-usb-gadget.sh 
&lt;span class="go"&gt;[  644.487501] g_ether gadget.0: HOST MAC f6:b0:84:e3:dc:c2
[  644.493125] g_ether gadget.0: MAC e2:87:7a:43:97:1d
[  644.498588] g_ether gadget.0: Ethernet Gadget, version: Memorial Day 2008
[  644.505565] g_ether gadget.0: g_ether ready
[  644.522283] PM: Cannot get wkup_m3_ipc handle
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly, list the available interface on BeagleBone Black:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;root@can:/home/can#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ip addr show
&lt;span class="gp"&gt;1: lo: &amp;lt;LOOPBACK,UP,LOWER_UP&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
&lt;span class="go"&gt;    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host noprefixroute 
       valid_lft forever preferred_lft forever
&lt;/span&gt;&lt;span class="gp"&gt;2: sit0@NONE: &amp;lt;NOARP&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mtu 1480 qdisc noop state DOWN group default qlen 1000
&lt;span class="go"&gt;    link/sit 0.0.0.0 brd 0.0.0.0
&lt;/span&gt;&lt;span class="gp"&gt;3: eth0: &amp;lt;BROADCAST,MULTICAST&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mtu 1500 qdisc noop state DOWN group default qlen 1000
&lt;span class="go"&gt;    link/ether 64:8c:bb:f2:25:78 brd ff:ff:ff:ff:ff:ff
&lt;/span&gt;&lt;span class="gp"&gt;4: usb0: &amp;lt;BROADCAST,MULTICAST,UP,LOWER_UP&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
&lt;span class="go"&gt;    link/ether e2:87:7a:43:97:1d brd ff:ff:ff:ff:ff:ff
    inet 198.168.7.2/24 brd 198.168.7.255 scope global usb0
       valid_lft forever preferred_lft forever
    inet6 fe80::e087:7aff:fe43:971d/64 scope link 
       valid_lft forever preferred_lft forever
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You see the "usb0" interface. That's enough for BeagleBone Black. Let's continue with host side. Open a new terminal and list the available interfaces on host:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;can@can:~$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ip addr show
&lt;span class="gp"&gt;1: lo: &amp;lt;LOOPBACK,UP,LOWER_UP&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
&lt;span class="go"&gt;    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host noprefixroute 
       valid_lft forever preferred_lft forever
&lt;/span&gt;&lt;span class="gp"&gt;2: enp3s0: &amp;lt;NO-CARRIER,BROADCAST,MULTICAST,UP&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mtu 1500 qdisc fq_codel state DOWN group default qlen 1000
&lt;span class="go"&gt;    link/ether e8:6a:64:19:45:15 brd ff:ff:ff:ff:ff:ff
&lt;/span&gt;&lt;span class="gp"&gt;3: wlp2s0: &amp;lt;BROADCAST,MULTICAST,UP,LOWER_UP&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mtu 1500 qdisc noqueue state UP group default qlen 1000
&lt;span class="go"&gt;    link/ether b0:fc:36:c1:cf:eb brd ff:ff:ff:ff:ff:ff
    inet 10.152.197.93/24 brd 10.152.197.255 scope global dynamic noprefixroute wlp2s0
       valid_lft 3521sec preferred_lft 3521sec
    inet6 fe80::18fc:91fe:ea80:8fad/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
&lt;/span&gt;&lt;span class="gp"&gt;4: docker0: &amp;lt;NO-CARRIER,BROADCAST,MULTICAST,UP&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mtu 1500 qdisc noqueue state DOWN group default 
&lt;span class="go"&gt;    link/ether fa:47:d4:7a:67:3e brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
&lt;/span&gt;&lt;span class="gp"&gt;13: enxf6b084e3dcc2: &amp;lt;BROADCAST,MULTICAST,UP,LOWER_UP&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mtu 1500 qdisc fq_codel state UP group default qlen 1000
&lt;span class="go"&gt;    link/ether f6:b0:84:e3:dc:c2 brd ff:ff:ff:ff:ff:ff
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;BeagleBone Black seems as "enxf6b084e3dcc2" for now. You probably see the different name. It doesn't matter. As wee did in BeagleBone Black, let's do the same things at host side:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;can@can:~$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ip addr flush dev enxf6b084e3dcc2
&lt;span class="gp"&gt;can@can:~$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;ip &lt;span class="nb"&gt;link set &lt;/span&gt;enxf6b084e3dcc2 up
&lt;span class="gp"&gt;can@can:~$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;ip addr add 198.168.7.1/24 dev enxf6b084e3dcc2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I assigned the IP address "198.168.7.1" to host (I did "198.168.7.2" for BeagleBone Black).&lt;/p&gt;

&lt;p&gt;Lastly, ping BeagleBone Black interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;can@can:~$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ping 198.168.7.2
&lt;span class="go"&gt;PING 198.168.7.2 (198.168.7.2) 56(84) bytes of data.
64 bytes from 198.168.7.2: icmp_seq=1 ttl=64 time=0.904 ms
64 bytes from 198.168.7.2: icmp_seq=2 ttl=64 time=0.351 ms
64 bytes from 198.168.7.2: icmp_seq=3 ttl=64 time=0.449 ms
64 bytes from 198.168.7.2: icmp_seq=4 ttl=64 time=0.478 ms
64 bytes from 198.168.7.2: icmp_seq=5 ttl=64 time=0.585 ms
64 bytes from 198.168.7.2: icmp_seq=6 ttl=64 time=0.477 ms
^C
--- 198.168.7.2 ping statistics ---
6 packets transmitted, 6 received, 0% packet loss, time 5114ms
rtt min/avg/max/mdev = 0.351/0.540/0.904/0.176 ms
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's okey 🥳🥳🥳🥳. You can connect to BeagleBone Black with ssh command for now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;can@can:~$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ssh can@198.168.7.2
&lt;span class="go"&gt;can@198.168.7.2's password: 
&lt;/span&gt;&lt;span class="gp"&gt;Linux can 6.14.0-ge8b471285262 #&lt;/span&gt;1 SMP Mon Apr 13 12:31:38 +03 2026 armv7l
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;The programs included with the Debian GNU/Linux system are free software;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sat Jan  1 00:43:51 2000 from 198.168.7.1
&lt;/span&gt;&lt;span class="gp"&gt;can@can:~$&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;span class="gp"&gt;can@can:~$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ls&lt;/span&gt;
&lt;span class="go"&gt;setup-usb-gadget.sh
&lt;/span&gt;&lt;span class="gp"&gt;can@can:~$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ..
&lt;span class="gp"&gt;can@can:/home$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ..
&lt;span class="gp"&gt;can@can:/$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ls&lt;/span&gt;
&lt;span class="go"&gt;bin  boot  dev  etc  home  lib  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You don't need anymore J1 serial header. You can use it within the ssh terminal for now. Also you can set the setup-usb-gadget.sh as startup script so that it runs automatically after the boot.&lt;/p&gt;

&lt;p&gt;In next tutorial, I will inspect the &lt;em&gt;uEnv.txt&lt;/em&gt; file and u-boot console. You can make many interesting tricks in there.&lt;/p&gt;

&lt;p&gt;Resources:&lt;/p&gt;

&lt;p&gt;Simmonds C., Mastering Embedded Linux Programming, Packt Publishing, 2015&lt;br&gt;
Embedded Linux system development training, Bootlin, 2024&lt;/p&gt;

</description>
      <category>linux</category>
      <category>computerscience</category>
      <category>programming</category>
      <category>lowcode</category>
    </item>
    <item>
      <title>Embedded Linux Development - Part 5</title>
      <dc:creator>Can Gulmez</dc:creator>
      <pubDate>Tue, 14 Apr 2026 13:18:52 +0000</pubDate>
      <link>https://dev.to/cangulmez/embedded-linux-development-part-5-13d9</link>
      <guid>https://dev.to/cangulmez/embedded-linux-development-part-5-13d9</guid>
      <description>&lt;p&gt;Until here, I've talked about the embedded Linux development in four stage: toolchain, bootloader, Linux kernel, rootfs. In this tutorial, I will create a SD card image including these and then run it in BeagleBone Black.&lt;/p&gt;

&lt;p&gt;Firstly, let's remember that what I've produced from these stages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;MLO&lt;/em&gt; (second-stage bootloader)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;u-boot.img&lt;/em&gt; (main bootloader)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;uEnv.txt&lt;/em&gt; (commands for the bootloader)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;zImage&lt;/em&gt; (compressed the kernel image)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;am335x-boneblack.dtb&lt;/em&gt; (device tree for the kernel)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Debian rootfs&lt;/em&gt; (including the kernel modules)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How can I create a SD card image including all of these?&lt;/p&gt;

&lt;p&gt;Firstly, I need to create two partitions, one for booting and second for rootfs. So plugin the SD card into the PC (I'm on Ubuntu) and create the partitions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;parted &lt;span class="nt"&gt;-s&lt;/span&gt; /dev/sdX mklabel msdos &lt;span class="c"&gt;# parition table and partitions&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;parted &lt;span class="nt"&gt;-s&lt;/span&gt; /dev/sdX mkpart primary fat32 1MiB 65MiB &lt;span class="c"&gt;# boot partition (FAT32, 64MB)&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;parted &lt;span class="nt"&gt;-s&lt;/span&gt; /dev/sdX &lt;span class="nb"&gt;set &lt;/span&gt;1 boot on &lt;span class="c"&gt;# make it first parititon&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;parted &lt;span class="nt"&gt;-s&lt;/span&gt; /dev/sdX mkpart primary ext4 65MiB 100% &lt;span class="c"&gt;# rootfs parititon (ext4, rest of SD card)&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;mkfs.vfat &lt;span class="nt"&gt;-F&lt;/span&gt; 32 &lt;span class="nt"&gt;-n&lt;/span&gt; boot /dev/sdX1 &lt;span class="c"&gt;# format the boot partition&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;mkfs.ext4 &lt;span class="nt"&gt;-L&lt;/span&gt; rootfs /dev/sdX2 &lt;span class="c"&gt;# format the rootfs partition&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In here, I created the "boot" partition which was formatted with FAT32 and "rootfs" partition with ext4. Why did I create two distinct partitions? The first reason is that the kernel loads and runs the rootfs. So the bootloader cannot reside in the rootfs because of the bootloader runs before the kernel. Second reason is that the bootloader works with FAT32 better (even if the FAT32 size is much bigger).&lt;/p&gt;

&lt;p&gt;After that, copy the MLO, u-boot.img, uEnv.txt, zImage, am335x-boneblack.dtb into the "boot" partition. Also copy the your rootfs content into the "rootfs" partition.&lt;/p&gt;

&lt;p&gt;That's it. The SD card is ready to run the BeagleBone Black. So plugin the SD card and then power up the board. Well how to enter into the Debian rootfs? There is a J1 header besides the P9. It's the serial port. Pin 1 is GND, 4 is RX and 5 is TX. Use FT232R converter to connect these pins to PC.&lt;/p&gt;

&lt;p&gt;To see the outputs, open a terminal and the type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;screen /dev/ttyUSBX 115200 &lt;span class="c"&gt;# or /dev/ttyACMX&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reboot the BeagleBone Black and then you will see the u-boot and the kernel messages. Lastly, you will see the login session:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkoq0bpsnhesqbe5fnwsj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkoq0bpsnhesqbe5fnwsj.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Type the "root" and the password (you set it in previous tutorial). That's it. You are in the BeagleBone Black terminal.&lt;/p&gt;

&lt;p&gt;You can do whatever you want after that 🥳🥳🥳.&lt;/p&gt;

&lt;p&gt;In the next tutorial, I will show that how to use &lt;em&gt;ssh&lt;/em&gt; command so that you can easily make connection over USB cable, not needing to J1 header.&lt;/p&gt;

&lt;p&gt;Resources:&lt;/p&gt;

&lt;p&gt;Simmonds C., Mastering Embedded Linux Programming, Packt Publishing, 2015&lt;br&gt;
Embedded Linux system development training, Bootlin, 2024&lt;/p&gt;

</description>
      <category>programming</category>
      <category>computerscience</category>
      <category>linux</category>
      <category>lowcode</category>
    </item>
    <item>
      <title>Embedded Linux Development - Part 4</title>
      <dc:creator>Can Gulmez</dc:creator>
      <pubDate>Mon, 13 Apr 2026 17:15:36 +0000</pubDate>
      <link>https://dev.to/cangulmez/embedded-linux-development-part-4-2j83</link>
      <guid>https://dev.to/cangulmez/embedded-linux-development-part-4-2j83</guid>
      <description>&lt;p&gt;In this tutorial, I will go with the fourth stage of embedded Linux development which is the rootfs.&lt;/p&gt;

&lt;p&gt;Every Linux-based system have a filesystem. If you are on GNU/Linux, you already probably know it and how it structured.&lt;/p&gt;

&lt;p&gt;Apart from that embedded Linux needs a few special applications to start up the system. The &lt;em&gt;init&lt;/em&gt; is the first program that runs on user-space so that its process ID always is 1. This init program is responsible for start the other user-space applications and services like shell. It generally resides at &lt;em&gt;/sbin/init&lt;/em&gt;, &lt;em&gt;/etc/init&lt;/em&gt;, &lt;em&gt;/bin/init&lt;/em&gt; or so on. The kernel try to find it and then run.&lt;/p&gt;

&lt;p&gt;The organization of a Linux rootfs in terms of directories is well-defined by the &lt;em&gt;Filesystem Hierarchy Standard&lt;/em&gt;. The general hierarchy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;/bin&lt;/em&gt;: Basic programs&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;/boot&lt;/em&gt;: Kernel images, configurations and booting tools&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;/dev&lt;/em&gt;: Device files&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;/etc&lt;/em&gt;: System-wide configuration&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;/home&lt;/em&gt;: Directory for the users home utilities&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;/lib&lt;/em&gt;: Basic libraries&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;/media&lt;/em&gt;: Mount points for removable media&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;/mnt&lt;/em&gt;: Mount point for a temporarily mounted filesystem&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;/proc&lt;/em&gt;: Mount point for the proc virtual filesystem&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;/root&lt;/em&gt;: How directory of the root user&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;/run&lt;/em&gt;: Run-time variable data&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;/sbin&lt;/em&gt;: Basic system programs&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;/sys&lt;/em&gt;: Mount point of the sysfs virtual filesystem&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;/tmp&lt;/em&gt;: Temporary files&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;/usr&lt;/em&gt;: User-specific utilities&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;/var&lt;/em&gt;: Variable data files, for system services&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So in summary, I need to create a Linux rootfs and then put the required applications in there. I also want to build a development environment. For example, I want to run python 3 scripts, compiling C/C++ programs, or so on. But how? &lt;/p&gt;

&lt;p&gt;There are three options here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Building everything from scratch&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A minimal &lt;em&gt;BusyBox&lt;/em&gt; rootfs&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A Debian rootfs with &lt;em&gt;debootstap&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Which option is for me? &lt;/p&gt;

&lt;p&gt;Building everything from scratch means that creating the directories and then fetch the every program, package, library by hand. It means the hell of package dependency! It's not for me.&lt;/p&gt;

&lt;p&gt;A minimal rootfs can be created with BusyBox easily. It can create the classic Linux directories and put the core utilities in there like &lt;em&gt;cp&lt;/em&gt;, &lt;em&gt;mkdir&lt;/em&gt;, &lt;em&gt;ls&lt;/em&gt; or so on. If you're making embedded Linux system first time and just focusing on a "running" system, BusyBox is for you. But I need more. I wanna create a development environment!&lt;/p&gt;

&lt;p&gt;The right tool is debootstrap program. It creates a base Debian rootfs including the utilities that we're using everyday like &lt;em&gt;apt&lt;/em&gt;, &lt;em&gt;systemctl&lt;/em&gt;, &lt;em&gt;vi&lt;/em&gt;, or so on. This Debian rootfs is around ~200MB, while BusyBox rootfs is ~1MB.&lt;/p&gt;

&lt;p&gt;By the way, if you want to go with BusyBox rootfs (while I'm not), below is the required commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git clone https://git.busybox.net/busybox
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;busybox
&lt;span class="nv"&gt;$ &lt;/span&gt;make &lt;span class="nv"&gt;ARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;arm &lt;span class="nv"&gt;CROSS_COMPILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;arm-linux-gnueabihf- defconfig
&lt;span class="nv"&gt;$ &lt;/span&gt;make &lt;span class="nv"&gt;ARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;arm &lt;span class="nv"&gt;CROSS_COMPILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;arm-linux-gnueabihf- &lt;span class="nt"&gt;-j&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;nproc&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;make &lt;span class="nv"&gt;ARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;arm &lt;span class="nv"&gt;CROSS_COMPILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;arm-linux-gnueabihf- menuconfig &lt;span class="c"&gt;# optional&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;make &lt;span class="nv"&gt;ARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;arm &lt;span class="nv"&gt;CROSS_COMPILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;arm-linux-gnueabihf- &lt;span class="nv"&gt;CONFIG_PREFIX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;path/to/linux/rootfs &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's focus on debootstrap. Firstly download it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;qemu-user-static debootstrap
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In here, I also installed &lt;em&gt;qemu-user-static&lt;/em&gt; which lets me to run the ARM binaries onto x86_64.&lt;/p&gt;

&lt;p&gt;Let's create the base Debian rootfs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;debootstrap &lt;span class="nt"&gt;--arch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;armhf &lt;span class="nt"&gt;--foreign&lt;/span&gt; bookworm path/to/linux/rootfs http://deb.debian.org/debian
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo chroot &lt;/span&gt;path/to/linux/rootfs /debootstrap/debootstrap &lt;span class="nt"&gt;--second-stage&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In here, &lt;em&gt;bookworm&lt;/em&gt; is the nickname of Debian 12 which is the last stable version. &lt;/p&gt;

&lt;p&gt;These two commands download the rootfs and then unpack it. So it takes some time (~30 minutes in my case). Don't forget, these just fetch the &lt;em&gt;required&lt;/em&gt; and &lt;em&gt;important&lt;/em&gt; packages from the Debian database, not fully OS.&lt;/p&gt;

&lt;p&gt;The rootfs is ready to be used. But there are some tricks that you always must do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo cp&lt;/span&gt; /usr/bin/qemu-arm-static &amp;lt;path/to/linux/rootfs&amp;gt;/usr/bin/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I also want to install the additional packages and make some settings. For example, you always must set the password. That means I need to run this rootfs on my Ubuntu host:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo chroot &lt;/span&gt;path/to/linux/rootfs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First thing you must is to update the password:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;root@can:/#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;passwd
&lt;span class="go"&gt;New password: 
Retype new password: 
passwd: password updated successfully
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install the additional packages if you want:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;root@can:/#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;gcc python3 vim openssh-server &lt;span class="c"&gt;# and what you need&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In here, make sure that you install the openssh-server. It's required for &lt;em&gt;ssh&lt;/em&gt; command. &lt;/p&gt;

&lt;p&gt;Lastly, I need to install the kernel modules in this rootfs. Go back to the kernel source and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;make &lt;span class="nv"&gt;ARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;arm &lt;span class="nv"&gt;CROSS_COMPILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;arm-linux-gnueabihf- &lt;span class="nv"&gt;INSTALL_MOD_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;path/to/linux/rootfs modules_install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. I created the proper Debian rootfs that I can make software development. In the next tutorial, I will use the all artifacts coming from u-boot, the kernel and the rootfs to make SD card image.&lt;/p&gt;

&lt;p&gt;Resources:&lt;/p&gt;

&lt;p&gt;Simmonds C., Mastering Embedded Linux Programming, Packt Publishing, 2015&lt;br&gt;
Embedded Linux system development training, Bootlin, 2024&lt;/p&gt;

</description>
      <category>programming</category>
      <category>lowcode</category>
      <category>linux</category>
      <category>computerscience</category>
    </item>
    <item>
      <title>Embedded Linux Development - Part 3</title>
      <dc:creator>Can Gulmez</dc:creator>
      <pubDate>Mon, 13 Apr 2026 14:02:29 +0000</pubDate>
      <link>https://dev.to/cangulmez/embedded-linux-development-part-3-6hm</link>
      <guid>https://dev.to/cangulmez/embedded-linux-development-part-3-6hm</guid>
      <description>&lt;p&gt;In this tutorial, I'll go with the third stage of embedded Linux development. That's the Linux kernel.&lt;/p&gt;

&lt;p&gt;It's the responsible for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Manage all the hardware resources: CPU, memory, I/O.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Provide a set of portable, architecture and hardware independent APIs to allow user space applications and libraries to use the hardware resources.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Handle concurrent accesses and usage of hardware resources set of system calls.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The kernel provides about 400 system calls that provide the services like opening the disk file, forking the new process, managing the memory or so on. These system calls are defined in &lt;em&gt;/usr/include/x86_64-linux-gnu/asm/unistd.h&lt;/em&gt; like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#define __NR_read 0
#define __NR_write 1
#define __NR_open 2
#define __NR_close 3
#define __NR_stat 4
#define __NR_fstat 5
#define __NR_lstat 6
#define __NR_poll 7
#define __NR_lseek 8
#define __NR_mmap 9
#define __NR_mprotect 10
#define __NR_munmap 11
#define __NR_brk 12
&lt;/span&gt;
&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In user-space applications, we generally don't use these system calls directly. These system calls are wrapped by the standard POSIX C library. If you're a programmer, you already know it.&lt;/p&gt;

&lt;p&gt;Let's start with downloading Linux kernel:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git clone https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I have the 6.14 kernel (slightly older, but doesn't matter). As you see that the kernel contains thousands of device drivers, filesystem drivers, network protocols and other configurable items. &lt;/p&gt;

&lt;p&gt;As I did previously at u-boot stage, the first thing is to configure the kernel according to BeagleBone Black over configuration files (ends with &lt;em&gt;_defconfig&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;Which configuration file should be used for BeagleBone Black? It's &lt;em&gt;omap2plus_defconfig&lt;/em&gt; under &lt;em&gt;linux/arch/arm/configs&lt;/em&gt; (OMAP is the processor family including the AM335x Sitara processor by TI).&lt;/p&gt;

&lt;p&gt;So let's configure the kernel:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;make &lt;span class="nv"&gt;ARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;arm &lt;span class="nv"&gt;CROSS_COMPILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;arm-linux-gnueabihf- omap2plus_defconfig
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will create the &lt;em&gt;.config&lt;/em&gt; and write the associated configs in it. &lt;/p&gt;

&lt;p&gt;As I said, this configuration file includes the generic AM335x Sitara processor configs. To customize and tailor the kernel further:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;make menuconfig &lt;span class="c"&gt;# or xconfig (for Qt-based)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will open the terminal-based GUI window to select/unselect the configurable items like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2a6ql4jcidk6pidcck8n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2a6ql4jcidk6pidcck8n.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you're unfamiliar or newer, I DON'T recommend it. But I need to make an important configuration in here about the &lt;em&gt;USB gadget&lt;/em&gt; support. As I will explain in the next tutorail, I wanna use the &lt;em&gt;ssh&lt;/em&gt; command to make connection with BeagleBone Black. If you don't make it, you're totally free.&lt;/p&gt;

&lt;p&gt;Navigate to &lt;em&gt;Device Drivers --&amp;gt; USB Support --&amp;gt; USB Gadget Support --&amp;gt; USB Gadget precomposed configurations --&amp;gt; Ethernet Gadget (with CDC Ethernet support)&lt;/em&gt;, type "M" and then exit by saving. It will create the virtual USB link so that I can use the ssh command to connect to BeagleBone Black. I will explain it in the last tutorial in detail.&lt;/p&gt;

&lt;p&gt;By the way, you will see the "*" and "M" marks as you navigate the configs. "*" means that the configs will be embedded into the kernel image, while "M" means that the configs is built as modules. These are plugins that can be loaded/unloaded dynamically at runtime to the kernel.&lt;/p&gt;

&lt;p&gt;After configured the kernel, for now, you're ready to build the required outputs. &lt;/p&gt;

&lt;p&gt;Which outputs exactly should be built from the kernel source? Three things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;zImage&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;am335x-boneblack.dtb&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;kernel modules&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;zImage is the compressed the Linux kernel image. am335x-boneblack.dtb is the &lt;em&gt;device tree blob&lt;/em&gt; that describes the hardware connected to the kernel. The kernel modules also are being compiled externally, not embedded into the kernel image.&lt;/p&gt;

&lt;p&gt;In here, I have to explain the device tree concept. It's the description of the hardware that the kernel manages at runtime. As you expect, the kernel must know the hardware that it will manage. It's written generally by the processor vendor or development board engineers. The device tree corresponding to BeagleBone Black is the &lt;em&gt;am335x-boneblack.dts&lt;/em&gt; under &lt;em&gt;linux/arch/arm/boot/dts/ti/omap&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;To produces these outputs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;make &lt;span class="nv"&gt;ARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;arm &lt;span class="nv"&gt;CROSS_COMPILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;arm-linux-gnueabihf- &lt;span class="nt"&gt;-j&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;nproc&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt; zImage dtbs modules
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will take for a while (~1 hours in my case). After that you will see the zImage under &lt;em&gt;linux/arch/arm/boot&lt;/em&gt; and am335x-boneblack.dtb under &lt;em&gt;linux/arch/arm/boot/dts/ti/omap&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;The kernel modules are compiled ending with &lt;em&gt;.ko&lt;/em&gt; suffix. After the rootfs is being created, I will install these kernel modules in it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;make &lt;span class="nv"&gt;ARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;arm &lt;span class="nv"&gt;CROSS_COMPILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;arm-linux-gnueabihf- &lt;span class="nv"&gt;INSTALL_MOD_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;path/to/linux/rootfs modules_install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But DON'T do it for now. I need to create a rootfs firstly and then install the kernel modules in there. I will show it in the next tutorial.&lt;/p&gt;

&lt;p&gt;That's it. I've produced the three essential components from the kernel source: zImage, am335x-boneblack.dtb, and kernel modules. In the next tutorial, I will interest with the rootfs.&lt;/p&gt;

&lt;p&gt;Resources:&lt;/p&gt;

&lt;p&gt;Simmonds C., Mastering Embedded Linux Programming, Packt Publishing, 2015&lt;br&gt;
Embedded Linux system development training, Bootlin, 2024&lt;/p&gt;

</description>
      <category>programming</category>
      <category>linux</category>
      <category>lowcode</category>
      <category>computerscience</category>
    </item>
    <item>
      <title>Embedded Linux Development - Part 2</title>
      <dc:creator>Can Gulmez</dc:creator>
      <pubDate>Sun, 12 Apr 2026 19:10:26 +0000</pubDate>
      <link>https://dev.to/cangulmez/embedded-linux-development-part-2-3klh</link>
      <guid>https://dev.to/cangulmez/embedded-linux-development-part-2-3klh</guid>
      <description>&lt;p&gt;In this post, I will continue the embedded Linux development series with second stage which is the bootloader.&lt;/p&gt;

&lt;p&gt;Firstly, a bit theoretical background.&lt;/p&gt;

&lt;p&gt;The bootloader is a piece of code responsible for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Basic hardware initialization&lt;/li&gt;
&lt;li&gt;Loading of an application binary, usually an operating
system kernel, from flash storage, from the network, or from another type of non-volatile storage&lt;/li&gt;
&lt;li&gt;Possible decompression of the application binary&lt;/li&gt;
&lt;li&gt;Execution of the application&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Besides these basic functions, most bootloaders provide a shell or menu:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Menu to select the operating system to load&lt;/li&gt;
&lt;li&gt;Shell with commands to load data from storage or network, inspect memory, perform hardware testing/diagnostics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Boot process highly is depended to processor. Let's focus on AM335x Sitara (ARM) booting sequence. &lt;/p&gt;

&lt;p&gt;Most embedded processors include a &lt;em&gt;ROM code&lt;/em&gt; that implements the initial step of the boot process. It's called the &lt;em&gt;first-stage loader&lt;/em&gt;. This ROM code is written by the processor vendor directly built into the processor. That means, it cannot be changed or updated by the others. It initializes the CPU and internal SRAM. It also searches the &lt;em&gt;MLO&lt;/em&gt; from NAND/NOR flash, from USB, from SD card, from eMMC, etc.&lt;/p&gt;

&lt;p&gt;MLO is a file that you need to produce from the bootloader source code. It's called also &lt;em&gt;second-program loader (SPL)&lt;/em&gt;. Its mission is to initialize the DDR RAM and run the main bootloader.&lt;/p&gt;

&lt;p&gt;The main bootloader initializes the hardware and then loads the Linux kernel and then jump to it. I will use the &lt;em&gt;U-Boot&lt;/em&gt;. It's the mostly used bootloader in embedded world.&lt;/p&gt;

&lt;p&gt;In summary, the booting process: &lt;em&gt;ROM code --&amp;gt; MLO (SPL) --&amp;gt; U-Boot --&amp;gt; Linux kernel&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;So after compiled the u-boot, I expect these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;MLO&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;u-boot.img&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's produce these.&lt;/p&gt;

&lt;p&gt;Firstly, download the u-boot:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git clone https://source.denx.de/u-boot/u-boot.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you look at the source code, you will see that the u-boot supports a lot of processors and boards. So first thing you should do is to configure the u-boot over configuration files (ends with &lt;em&gt;*_defconfig&lt;/em&gt;) under &lt;em&gt;u-boot/configs&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;But which exactly configuration file corresponds to BeagleBone Black? The answer is &lt;em&gt;am335x_evm_defconfig&lt;/em&gt;. It's generic AM335x Sitara processor configuration file.&lt;/p&gt;

&lt;p&gt;To use this configuration file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;make am335x_evm_defconfig
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will create the &lt;em&gt;.config&lt;/em&gt; file and write the configs in it. The important point is that you never edit this file by hand.&lt;/p&gt;

&lt;p&gt;To customize and tailor this configs further:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;make menuconfig     &lt;span class="c"&gt;# or xconfig (for Qt-based)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will open the terminal-based GUI to select/unselect the configs. If you are unfamiliar or newer, you should NOT do it. Because it will show the tons of different configs and it can seem messy. The previous command already made the generic required configs.&lt;/p&gt;

&lt;p&gt;After setting up the configs, let's build the outputs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;make &lt;span class="nv"&gt;ARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;arm &lt;span class="nv"&gt;CROSS_COMPILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;arm-linux-gnueabihf- 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will take for a while. Because it will compile the tons of source file and then link them together. The output will be like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;(&lt;/span&gt;...&lt;span class="o"&gt;)&lt;/span&gt;

  AR      spl/fs/fat/built-in.o
  CC      spl/fs/fs_internal.o
  AR      spl/fs/built-in.o
  CC      spl/net/arp.o
  CC      spl/net/bootp.o
  CC      spl/net/eth-uclass.o
  CC      spl/net/eth_common.o
  CC      spl/net/net.o
  CC      spl/net/ping.o
  CC      spl/net/tftp.o
  AR      spl/net/built-in.o
  LDS     spl/u-boot-spl.lds
  LD      spl/u-boot-spl
  OBJCOPY spl/u-boot-spl-nodtb.bin
  COPY    spl/u-boot-spl.bin
  MKIMAGE MLO
  MKIMAGE MLO.byteswap
  SYM     spl/u-boot-spl.sym
  MKIMAGE u-boot-dtb.img
  OFCHK   .config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that you can see the u-boot/MLO, u-boot/u-boot.img and a lots of other files. &lt;/p&gt;

&lt;p&gt;As I said before, I need the MLO and u-boot.img and will use these in further. For now, just keeps these in mind.&lt;/p&gt;

&lt;p&gt;There is also one more important file that I need. It's &lt;em&gt;uEnv.txt&lt;/em&gt; and used by the u-boot when loading the Linux kernel. It consists of the key-value pairs that tell some command to u-boot. So create a new file named of it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;vim uEnv.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And write the following commands in it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;bootpart&lt;/span&gt;=&lt;span class="m"&gt;0&lt;/span&gt;:&lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="n"&gt;devtype&lt;/span&gt;=&lt;span class="n"&gt;mmc&lt;/span&gt;
&lt;span class="n"&gt;bootdir&lt;/span&gt;=
&lt;span class="n"&gt;bootfile&lt;/span&gt;=&lt;span class="n"&gt;zImage&lt;/span&gt;
&lt;span class="n"&gt;bootpartition&lt;/span&gt;=&lt;span class="n"&gt;mmcblk0p2&lt;/span&gt;
&lt;span class="n"&gt;console&lt;/span&gt;=&lt;span class="n"&gt;ttyS0&lt;/span&gt;,&lt;span class="m"&gt;115200&lt;/span&gt;&lt;span class="n"&gt;n8&lt;/span&gt;
&lt;span class="n"&gt;loadaddr&lt;/span&gt;=&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x82000000&lt;/span&gt;
&lt;span class="n"&gt;fdtaddr&lt;/span&gt;=&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x88000000&lt;/span&gt;
&lt;span class="n"&gt;set_mmc1&lt;/span&gt;=&lt;span class="n"&gt;if&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; $&lt;span class="n"&gt;board_name&lt;/span&gt; = &lt;span class="n"&gt;A33515BB&lt;/span&gt;; &lt;span class="n"&gt;then&lt;/span&gt; &lt;span class="n"&gt;setenv&lt;/span&gt; &lt;span class="n"&gt;bootpartition&lt;/span&gt; &lt;span class="n"&gt;mmcblk1p2&lt;/span&gt;; &lt;span class="n"&gt;fi&lt;/span&gt;
&lt;span class="n"&gt;set_bootargs&lt;/span&gt;=&lt;span class="n"&gt;setenv&lt;/span&gt; &lt;span class="n"&gt;bootargs&lt;/span&gt; &lt;span class="n"&gt;console&lt;/span&gt;=${&lt;span class="n"&gt;console&lt;/span&gt;} &lt;span class="n"&gt;root&lt;/span&gt;=/&lt;span class="n"&gt;dev&lt;/span&gt;/${&lt;span class="n"&gt;bootpartition&lt;/span&gt;} &lt;span class="n"&gt;rw&lt;/span&gt; &lt;span class="n"&gt;rootfstype&lt;/span&gt;=&lt;span class="n"&gt;ext4&lt;/span&gt; &lt;span class="n"&gt;rootwait&lt;/span&gt;
&lt;span class="n"&gt;uenvcmd&lt;/span&gt;=&lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="n"&gt;set_mmc1&lt;/span&gt;; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="n"&gt;set_bootargs&lt;/span&gt;;&lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="n"&gt;loadimage&lt;/span&gt;;&lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="n"&gt;loadfdt&lt;/span&gt;;&lt;span class="n"&gt;printenv&lt;/span&gt; &lt;span class="n"&gt;bootargs&lt;/span&gt;;&lt;span class="n"&gt;bootz&lt;/span&gt; ${&lt;span class="n"&gt;loadaddr&lt;/span&gt;} - ${&lt;span class="n"&gt;fdtaddr&lt;/span&gt;}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At the end of this series, you will fully understand what these are. But basically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;the console name is set to ttyS0 and baud rate to 115200.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;the Linux kernel name is defined as &lt;em&gt;zImage&lt;/em&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;the address that Linux kernel image will be placed is set to 0x82000000 and the address that device tree blob will be placed to 0x88000000.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;set the boot environment and load the Linux kernel with &lt;em&gt;bootz&lt;/em&gt; command.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Save it and then keep this file in mind as being MLO and u-boot.img.&lt;/p&gt;

&lt;p&gt;That's it. You've produced the three components related to bootloader stage. In next post, I will interest with Linux kernel itself.&lt;/p&gt;

&lt;p&gt;Resources:&lt;/p&gt;

&lt;p&gt;Simmonds C., Mastering Embedded Linux Programming, Packt Publishing, 2015&lt;br&gt;
Embedded Linux system development training, Bootlin, 2024&lt;/p&gt;

</description>
      <category>linux</category>
      <category>programming</category>
      <category>lowcode</category>
      <category>computerscience</category>
    </item>
    <item>
      <title>Embedded Linux Development - Part 1</title>
      <dc:creator>Can Gulmez</dc:creator>
      <pubDate>Sun, 12 Apr 2026 12:53:51 +0000</pubDate>
      <link>https://dev.to/cangulmez/embedded-linux-development-1-3pbc</link>
      <guid>https://dev.to/cangulmez/embedded-linux-development-1-3pbc</guid>
      <description>&lt;p&gt;In today, I'm beginning a new series about embedded Linux development. I'll show that how to build an end-to-end embedded Linux system from scratch by hand.&lt;/p&gt;

&lt;p&gt;I'll fetch the associated every stuffs from source code and then build the corresponding outputs.&lt;/p&gt;

&lt;p&gt;I will target the &lt;strong&gt;BeagleBone Black Rev C&lt;/strong&gt; board. I will compile the everything for that board. So you need the following things for this series:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;BeagleBone Black Rev C&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;USB Mini-B to USB-A cable&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;FTDI FT232R converter&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;SD card&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Overall, embedded Linux development consists of four components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Toolchain&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Bootloader&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Linux kernel&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Rootfs&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this post, I will explain the toolchain that I need for all development sequence.&lt;/p&gt;

&lt;p&gt;The toolchain is the first element of embedded Linux and the starting point of the project.&lt;/p&gt;

&lt;p&gt;A toolchain is the set of tools that compiles source code into executables that can run on your target device, and includes many binaries for the different purposes. Usually, toolchains for Linux are based on components from the GNU project. A standard GNU toolchain consists of three main components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Binutils&lt;/em&gt; is a set of tools to generate and manipulate binaries for a given architecture. Common binaries: &lt;em&gt;as&lt;/em&gt;, &lt;em&gt;ld&lt;/em&gt;, &lt;em&gt;ar&lt;/em&gt;, &lt;em&gt;randlib&lt;/em&gt;, &lt;em&gt;objdump&lt;/em&gt;, &lt;em&gt;readelf&lt;/em&gt;, &lt;em&gt;size&lt;/em&gt;, &lt;em&gt;nm&lt;/em&gt;, &lt;em&gt;strings&lt;/em&gt;, &lt;em&gt;strip&lt;/em&gt;, etc.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;GCC&lt;/em&gt; is the main compiler.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;C library&lt;/em&gt; is used to interract with the kernel. The programming interface to the UNIX operating system is defined in the C language, which is defined by the POSIX standards. The C library is the implementation of the interface.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In here, there are two types of toolchain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Native&lt;/em&gt;: This toolchain runs on the same type of system.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Cross&lt;/em&gt;: This toolchain run on a different type of system than the target.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Almost all embedded Linux development is done using a cross development toolchain. Because doing embedded development, there is always a split between:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The &lt;em&gt;host&lt;/em&gt;, the development workstation&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;em&gt;target&lt;/em&gt;, which is the embedded system&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They are connected by various means: almost always a serial line for debugging purposes, frequently a network connection, sometimes a JTAG interface for low-level stuffs.&lt;/p&gt;

&lt;p&gt;Many UNIX/Linux toolchains rely on architecture tuple names to identify machines. You probably compiled many programs on your host already and used the &lt;em&gt;gcc&lt;/em&gt; command. But it's actually a shorthand. You can exactly see it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;gcc &lt;span class="nt"&gt;-dumpmachine&lt;/span&gt;
&lt;span class="go"&gt;x86_64-linux-gnu
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Other examples: &lt;em&gt;arm-linux-gnueabihf&lt;/em&gt;, &lt;em&gt;mips64el-linux-gnu&lt;/em&gt;, &lt;em&gt;arm-none-eabi-&lt;/em&gt; etc.&lt;/p&gt;

&lt;p&gt;These tuples are 3 or 4 parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The architecture name: &lt;em&gt;arm&lt;/em&gt;, &lt;em&gt;riscv&lt;/em&gt;, &lt;em&gt;mips64el&lt;/em&gt;, etc.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Optionally, a vendor name, which is free-form string.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An operating system name, or &lt;em&gt;none&lt;/em&gt; when not targeting an operating system.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Of course, these are the pre-built toolchains. If you want, you can also create your own toolchain with &lt;em&gt;crosstool-ng&lt;/em&gt;. It's another post topic. But shortly, when building a toolchain, the ABI used to generate binaries needs to be defined. ABI, &lt;em&gt;Application Binary Interface&lt;/em&gt;, defines the calling conventions (how function arguments are passed, how the return value is passed, how system calls are made or so on) and the organization of structures. All binaries in a system are typically compiled with the same ABI, and the kernel must understand this ABI.&lt;/p&gt;

&lt;p&gt;Anyway, I gave you the enough theoretical toolchain background. Let's go with our concern.&lt;/p&gt;

&lt;p&gt;Which toolchain should be used for BeagleBone Black?&lt;/p&gt;

&lt;p&gt;You have to know the used ARM processor in here. BeageBone Black has AM335x Sitara processor which is based on ARM-A8 (ARMv7), 32-bit architecture. So the toolchain for that is the &lt;em&gt;gcc-arm-linux-gnueabihf&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The first thing in implementing embedded Linux is to install it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;gcc-arm-linux-gnueabihf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that validate it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;arm-linux-gnueabihf-gcc &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;span class="go"&gt;arm-linux-gnueabihf-gcc (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0
Copyright (C) 2023 Free Software Foundation, Inc.
&lt;/span&gt;&lt;span class="gp"&gt;This is free software;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;see the &lt;span class="nb"&gt;source &lt;/span&gt;&lt;span class="k"&gt;for &lt;/span&gt;copying conditions.  There is NO
&lt;span class="gp"&gt;warranty;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;not even &lt;span class="k"&gt;for &lt;/span&gt;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. You have the required toolchain and ready to go with the bootloader.&lt;/p&gt;

&lt;p&gt;Resources:&lt;/p&gt;

&lt;p&gt;Simmonds C., Mastering Embedded Linux Programming, Packt Publishing, 2015&lt;br&gt;
Embedded Linux system development training, Bootlin, 2024&lt;/p&gt;

</description>
      <category>linux</category>
      <category>programming</category>
      <category>computerscience</category>
      <category>lowcode</category>
    </item>
    <item>
      <title>POSIX Shared Memory</title>
      <dc:creator>Can Gulmez</dc:creator>
      <pubDate>Wed, 08 Apr 2026 12:47:19 +0000</pubDate>
      <link>https://dev.to/cangulmez/posix-shared-memory-1l1n</link>
      <guid>https://dev.to/cangulmez/posix-shared-memory-1l1n</guid>
      <description>&lt;p&gt;POSIX shared memory allows to us to share a mapped region between unrelated processes without needing to create a corresponding  file.&lt;/p&gt;

&lt;p&gt;Linux uses a dedicated &lt;code&gt;tmpfs&lt;/code&gt; file system mounted under the directory &lt;code&gt;/dev/shm&lt;/code&gt;. This file system has kernel persistance - the shared memory objects that it contains will persists even if no process currently has them open, but they will be lost if the system is shut down.&lt;/p&gt;

&lt;p&gt;To use a POSIX shared memory object, we perform two steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Use the &lt;code&gt;shm_open()&lt;/code&gt; function to open an object with a specified name. The &lt;code&gt;shm_open()&lt;/code&gt; function is analogous to the &lt;code&gt;open()&lt;/code&gt; system call. It either creates a new shared memory object or opens an existing object. As its function result, &lt;code&gt;shm_open()&lt;/code&gt; returns a file descriptor referring to the object.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pass the file descriptor obtained in the previous step in a call to &lt;code&gt;mmap()&lt;/code&gt; that specifies &lt;code&gt;MAP_SHARED&lt;/code&gt; in the flags argument. This maps the shared memory object into the process's virtual address space.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;sys/mman.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;sys/stat.h&amp;gt;&lt;/span&gt;&lt;span class="c1"&gt;        /* For mode constants */&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;fcntl.h&amp;gt;&lt;/span&gt;&lt;span class="c1"&gt;           /* For O_* constants */&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;shm_open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;oflag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mode_t&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;shm_unlink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;name&lt;/code&gt; argument identifies the shared memory object to be created or opened. The &lt;code&gt;oflags&lt;/code&gt; argument is a mask of bits of O_* as being in &lt;code&gt;open()&lt;/code&gt; system call.&lt;/p&gt;

&lt;p&gt;At any point, we can apply &lt;code&gt;fstat()&lt;/code&gt; to the file descriptor returned by &lt;code&gt;shm_open()&lt;/code&gt; in order to obtain a &lt;code&gt;stat&lt;/code&gt; structure whose contain information about the shared memory object.&lt;/p&gt;

&lt;p&gt;Example of creating a POSIX shared memory is &lt;a href="https://github.com/CanGulmez/Linux-Programming-Interface/blob/main/pshm/pshm_create.c" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After created the memory object, we of course want to read and write the data into that. Data reading program is &lt;a href="https://github.com/CanGulmez/Linux-Programming-Interface/blob/main/pshm/pshm_write.c" rel="noopener noreferrer"&gt;here&lt;/a&gt; and writing program is &lt;a href="https://github.com/CanGulmez/Linux-Programming-Interface/blob/main/pshm/pshm_read.c" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;SUSv3 requires that POSIX shared memory objects have at least kernel persistence; that is, they continue to exist until they are explicitly removed or the system is rebooted. When a shared memory object is no longer required, it should be removed using &lt;code&gt;shm_unlink()&lt;/code&gt;. The example program of its usage is &lt;a href="https://github.com/CanGulmez/Linux-Programming-Interface/blob/main/pshm/pshm_unlink.c" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In summary, a POSIX shared memory object is used to share a region of memory between unrelated processes without creating an underlying disk file. To do this, we replace the call to &lt;code&gt;open()&lt;/code&gt; that normally precedes &lt;code&gt;mmap()&lt;/code&gt; with a call to &lt;code&gt;shm_open()&lt;/code&gt;. The &lt;code&gt;shm_open()&lt;/code&gt; call creates a file in a memory-based file system, and we can employ traditional file descriptor system calls to perform various operations on this virtual file. In particular, &lt;code&gt;ftruncate()&lt;/code&gt; must be used to set the size of the shared memory object, since initially it has a length of zero.&lt;/p&gt;

</description>
      <category>linux</category>
      <category>lowcode</category>
      <category>gnu</category>
      <category>computerscience</category>
    </item>
    <item>
      <title>Flashing and Debugging A Firmware in Detail</title>
      <dc:creator>Can Gulmez</dc:creator>
      <pubDate>Tue, 10 Mar 2026 20:38:32 +0000</pubDate>
      <link>https://dev.to/cangulmez/flashing-and-debugging-a-firmware-in-detail-d3f</link>
      <guid>https://dev.to/cangulmez/flashing-and-debugging-a-firmware-in-detail-d3f</guid>
      <description>&lt;p&gt;In this tutorial, I will inspect, flash and debug a firmware written for STM32F446RE microcontroller. To accomplish this, we need some dedicated tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;openocd&lt;/li&gt;
&lt;li&gt;arm-none-eabi-*&lt;/li&gt;
&lt;li&gt;gdb-multiarch&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;openocd is the primarily tool that we have to get. It's used as bridge between your host machine and debugger hardware. (I'm using use ST-Link hardware in this time). I will use it to connect to the debugger hardware. arm-none-eabi-* tools are the ARM toolchain   used in development of the firmware. gdb-multiarch is the debugger too.&lt;/p&gt;

&lt;p&gt;You can get these tools:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;openocd gcc-arm-none-eabi gdb-multiarch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note: I'm on Ubuntu 24.04, gcc-arm-none-eabi tools don't include the gdb debugger like arm-none-eabi-gdb. So that gdb-multiarch is being installed externally. On some distribution, the gdb debugger comes with gcc-arm-none-eabi.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Suppose that I have a firmware called "firmware.elf" and wanna inspect it as first step. &lt;/p&gt;

&lt;p&gt;The first thing that you should do probably is to determine the firmware itself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;file firmware.elf
&lt;span class="go"&gt;firmware.elf: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, with debug_info, not stripped
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;em&gt;file&lt;/em&gt; command simply outputs the firmware properties like the endiannes, architecture, or so on. You can see easily that this firmware was written for 32-bit ARM Cortex.&lt;/p&gt;

&lt;p&gt;We can see also the section sizes (in bytes) of the firmware with &lt;em&gt;arm-none-eabi-size&lt;/em&gt; command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;arm-none-eabi-size firmware.elf
&lt;span class="go"&gt;   text    data     bss     dec     hex filename
   5252      20    1732    7004    1b5c firmware.elf
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are not familiar with sections of the executables, I've wrote many tutorials that explains the ELF executable. You can look at there.&lt;/p&gt;

&lt;p&gt;If you exactly wanna see the contents of the firmware, &lt;em&gt;arm-none-eabi-objdump&lt;/em&gt; is the primarily tool for that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight armasm"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="nb"&gt;arm&lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;eabi&lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;objdump&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;j&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;text&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt; &lt;span class="nv"&gt;firmware&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;elf&lt;/span&gt;

&lt;span class="nl"&gt;firmware&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nl"&gt;elf&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;     &lt;span class="nb"&gt;file&lt;/span&gt; &lt;span class="nv"&gt;format&lt;/span&gt; &lt;span class="nv"&gt;elf32&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;littlearm&lt;/span&gt;


&lt;span class="nl"&gt;Disassembly&lt;/span&gt; &lt;span class="nb"&gt;of&lt;/span&gt; &lt;span class="nv"&gt;section&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;text&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;

&lt;span class="err"&gt;(...)&lt;/span&gt;

&lt;span class="nl"&gt;0800079c&lt;/span&gt; &lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;main&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;:&lt;/span&gt;
 &lt;span class="err"&gt;800079&lt;/span&gt;&lt;span class="nb"&gt;c&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;   &lt;span class="nv"&gt;b500&lt;/span&gt;        &lt;span class="nv"&gt;push&lt;/span&gt;    &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;lr&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
 &lt;span class="err"&gt;800079&lt;/span&gt;&lt;span class="nb"&gt;e&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;   &lt;span class="nv"&gt;b091&lt;/span&gt;        &lt;span class="nv"&gt;sub&lt;/span&gt; &lt;span class="nv"&gt;sp&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;68&lt;/span&gt; &lt;span class="no"&gt;@&lt;/span&gt; &lt;span class="mh"&gt;0x44&lt;/span&gt;
 &lt;span class="err"&gt;80007&lt;/span&gt;&lt;span class="nb"&gt;a0&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;   &lt;span class="nv"&gt;f000&lt;/span&gt; &lt;span class="nv"&gt;f8ac&lt;/span&gt;   &lt;span class="nv"&gt;bl&lt;/span&gt;  &lt;span class="mi"&gt;80008&lt;/span&gt;&lt;span class="nv"&gt;fc&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;HAL_Init&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="err"&gt;80007&lt;/span&gt;&lt;span class="nb"&gt;a4&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;   &lt;span class="nv"&gt;f000&lt;/span&gt; &lt;span class="nv"&gt;f82c&lt;/span&gt;   &lt;span class="nv"&gt;bl&lt;/span&gt;  &lt;span class="mi"&gt;8000800&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;configOscClk&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="err"&gt;80007&lt;/span&gt;&lt;span class="nb"&gt;a8&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;   &lt;span class="nv"&gt;f000&lt;/span&gt; &lt;span class="nv"&gt;f844&lt;/span&gt;   &lt;span class="nv"&gt;bl&lt;/span&gt;  &lt;span class="mi"&gt;8000834&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;configDebugPort&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="err"&gt;80007&lt;/span&gt;&lt;span class="nb"&gt;ac&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;   &lt;span class="mi"&gt;4911&lt;/span&gt;        &lt;span class="nv"&gt;ldr&lt;/span&gt; &lt;span class="nv"&gt;r1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;pc&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;68&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;   &lt;span class="no"&gt;@&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;80007&lt;/span&gt;&lt;span class="nv"&gt;f4&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mh"&gt;0x58&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;)&lt;/span&gt;
 &lt;span class="err"&gt;80007&lt;/span&gt;&lt;span class="nb"&gt;ae&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;   &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="nv"&gt;d12&lt;/span&gt;        &lt;span class="nv"&gt;ldr&lt;/span&gt; &lt;span class="nv"&gt;r5&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;pc&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;72&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;   &lt;span class="no"&gt;@&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;80007&lt;/span&gt;&lt;span class="nv"&gt;f8&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mh"&gt;0x5c&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;)&lt;/span&gt;
 &lt;span class="err"&gt;80007&lt;/span&gt;&lt;span class="nb"&gt;b0&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;   &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="nv"&gt;c12&lt;/span&gt;        &lt;span class="nv"&gt;ldr&lt;/span&gt; &lt;span class="nv"&gt;r4&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;pc&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;72&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;   &lt;span class="no"&gt;@&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;80007&lt;/span&gt;&lt;span class="nv"&gt;fc&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mh"&gt;0x60&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;)&lt;/span&gt;
 &lt;span class="err"&gt;80007&lt;/span&gt;&lt;span class="nb"&gt;b2&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;   &lt;span class="mi"&gt;4668&lt;/span&gt;        &lt;span class="nv"&gt;mov&lt;/span&gt; &lt;span class="nv"&gt;r0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;sp&lt;/span&gt;
 &lt;span class="err"&gt;80007&lt;/span&gt;&lt;span class="nb"&gt;b4&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;   &lt;span class="nv"&gt;f7ff&lt;/span&gt; &lt;span class="nv"&gt;ff08&lt;/span&gt;   &lt;span class="nv"&gt;bl&lt;/span&gt;  &lt;span class="mi"&gt;80005&lt;/span&gt;&lt;span class="nv"&gt;c8&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;strcpy&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="err"&gt;80007&lt;/span&gt;&lt;span class="nb"&gt;b8&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;   &lt;span class="mi"&gt;4668&lt;/span&gt;        &lt;span class="nv"&gt;mov&lt;/span&gt; &lt;span class="nv"&gt;r0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;sp&lt;/span&gt;
 &lt;span class="err"&gt;80007&lt;/span&gt;&lt;span class="nb"&gt;ba&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;   &lt;span class="nv"&gt;f7ff&lt;/span&gt; &lt;span class="nv"&gt;ff81&lt;/span&gt;   &lt;span class="nv"&gt;bl&lt;/span&gt;  &lt;span class="mi"&gt;80006&lt;/span&gt;&lt;span class="nv"&gt;c0&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;strlen&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="err"&gt;80007&lt;/span&gt;&lt;span class="nb"&gt;be&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;   &lt;span class="nv"&gt;f04f&lt;/span&gt; &lt;span class="mi"&gt;33&lt;/span&gt;&lt;span class="nv"&gt;ff&lt;/span&gt;   &lt;span class="nv"&gt;mov&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;w&lt;/span&gt;   &lt;span class="nv"&gt;r3&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;4294967295&lt;/span&gt; &lt;span class="no"&gt;@&lt;/span&gt; &lt;span class="mh"&gt;0xffffffff&lt;/span&gt;
 &lt;span class="err"&gt;80007&lt;/span&gt;&lt;span class="nb"&gt;c2&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;   &lt;span class="nv"&gt;b282&lt;/span&gt;        &lt;span class="nv"&gt;uxth&lt;/span&gt;    &lt;span class="nv"&gt;r2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;r0&lt;/span&gt;
 &lt;span class="err"&gt;80007&lt;/span&gt;&lt;span class="nb"&gt;c4&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;   &lt;span class="mi"&gt;4669&lt;/span&gt;        &lt;span class="nv"&gt;mov&lt;/span&gt; &lt;span class="nv"&gt;r1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;sp&lt;/span&gt;
 &lt;span class="err"&gt;80007&lt;/span&gt;&lt;span class="nb"&gt;c6&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;   &lt;span class="mi"&gt;480&lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt;        &lt;span class="nv"&gt;ldr&lt;/span&gt; &lt;span class="nv"&gt;r0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;pc&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;52&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;   &lt;span class="no"&gt;@&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;80007&lt;/span&gt;&lt;span class="nv"&gt;fc&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mh"&gt;0x60&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;)&lt;/span&gt;
 &lt;span class="err"&gt;80007&lt;/span&gt;&lt;span class="nb"&gt;c8&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;   &lt;span class="nv"&gt;f000&lt;/span&gt; &lt;span class="nv"&gt;fdc2&lt;/span&gt;   &lt;span class="nv"&gt;bl&lt;/span&gt;  &lt;span class="mi"&gt;8001350&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;HAL_UART_Transmit&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="err"&gt;80007&lt;/span&gt;&lt;span class="nb"&gt;cc&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;   &lt;span class="mi"&gt;4629&lt;/span&gt;        &lt;span class="nv"&gt;mov&lt;/span&gt; &lt;span class="nv"&gt;r1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;r5&lt;/span&gt;
 &lt;span class="err"&gt;80007&lt;/span&gt;&lt;span class="nb"&gt;ce&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;   &lt;span class="mi"&gt;4668&lt;/span&gt;        &lt;span class="nv"&gt;mov&lt;/span&gt; &lt;span class="nv"&gt;r0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;sp&lt;/span&gt;
 &lt;span class="err"&gt;80007&lt;/span&gt;&lt;span class="nb"&gt;d0&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;   &lt;span class="nv"&gt;f7ff&lt;/span&gt; &lt;span class="nv"&gt;fefa&lt;/span&gt;   &lt;span class="nv"&gt;bl&lt;/span&gt;  &lt;span class="mi"&gt;80005&lt;/span&gt;&lt;span class="nv"&gt;c8&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;strcpy&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="err"&gt;80007&lt;/span&gt;&lt;span class="nb"&gt;d4&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;   &lt;span class="mi"&gt;4668&lt;/span&gt;        &lt;span class="nv"&gt;mov&lt;/span&gt; &lt;span class="nv"&gt;r0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;sp&lt;/span&gt;
 &lt;span class="err"&gt;80007&lt;/span&gt;&lt;span class="nb"&gt;d6&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;   &lt;span class="nv"&gt;f7ff&lt;/span&gt; &lt;span class="nv"&gt;ff73&lt;/span&gt;   &lt;span class="nv"&gt;bl&lt;/span&gt;  &lt;span class="mi"&gt;80006&lt;/span&gt;&lt;span class="nv"&gt;c0&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;strlen&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="err"&gt;80007&lt;/span&gt;&lt;span class="nb"&gt;da&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;   &lt;span class="nv"&gt;f04f&lt;/span&gt; &lt;span class="mi"&gt;33&lt;/span&gt;&lt;span class="nv"&gt;ff&lt;/span&gt;   &lt;span class="nv"&gt;mov&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;w&lt;/span&gt;   &lt;span class="nv"&gt;r3&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;4294967295&lt;/span&gt; &lt;span class="no"&gt;@&lt;/span&gt; &lt;span class="mh"&gt;0xffffffff&lt;/span&gt;
 &lt;span class="err"&gt;80007&lt;/span&gt;&lt;span class="nb"&gt;de&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;   &lt;span class="nv"&gt;b282&lt;/span&gt;        &lt;span class="nv"&gt;uxth&lt;/span&gt;    &lt;span class="nv"&gt;r2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;r0&lt;/span&gt;
 &lt;span class="err"&gt;80007&lt;/span&gt;&lt;span class="nb"&gt;e0&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;   &lt;span class="mi"&gt;4669&lt;/span&gt;        &lt;span class="nv"&gt;mov&lt;/span&gt; &lt;span class="nv"&gt;r1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;sp&lt;/span&gt;
 &lt;span class="err"&gt;80007&lt;/span&gt;&lt;span class="nb"&gt;e2&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;   &lt;span class="mi"&gt;4620&lt;/span&gt;        &lt;span class="nv"&gt;mov&lt;/span&gt; &lt;span class="nv"&gt;r0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;r4&lt;/span&gt;
 &lt;span class="err"&gt;80007&lt;/span&gt;&lt;span class="nb"&gt;e4&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;   &lt;span class="nv"&gt;f000&lt;/span&gt; &lt;span class="nv"&gt;fdb4&lt;/span&gt;   &lt;span class="nv"&gt;bl&lt;/span&gt;  &lt;span class="mi"&gt;8001350&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;HAL_UART_Transmit&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="err"&gt;80007&lt;/span&gt;&lt;span class="nb"&gt;e8&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;   &lt;span class="nv"&gt;f44f&lt;/span&gt; &lt;span class="mi"&gt;707&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;   &lt;span class="nv"&gt;mov&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;w&lt;/span&gt;   &lt;span class="nv"&gt;r0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;   &lt;span class="no"&gt;@&lt;/span&gt; &lt;span class="mh"&gt;0x3e8&lt;/span&gt;
 &lt;span class="err"&gt;80007&lt;/span&gt;&lt;span class="nb"&gt;ec&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;   &lt;span class="nv"&gt;f000&lt;/span&gt; &lt;span class="nv"&gt;f8b2&lt;/span&gt;   &lt;span class="nv"&gt;bl&lt;/span&gt;  &lt;span class="mi"&gt;8000954&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;HAL_Delay&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="err"&gt;80007&lt;/span&gt;&lt;span class="nb"&gt;f0&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;   &lt;span class="nv"&gt;e7ec&lt;/span&gt;        &lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt; &lt;span class="mi"&gt;80007&lt;/span&gt;&lt;span class="nb"&gt;cc&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mh"&gt;0x30&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="err"&gt;80007&lt;/span&gt;&lt;span class="nb"&gt;f2&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;   &lt;span class="nv"&gt;bf00&lt;/span&gt;        &lt;span class="nv"&gt;nop&lt;/span&gt;
 &lt;span class="err"&gt;80007&lt;/span&gt;&lt;span class="nb"&gt;f4&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;   &lt;span class="mi"&gt;0800146&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;    &lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;word&lt;/span&gt;   &lt;span class="mh"&gt;0x0800146c&lt;/span&gt;
 &lt;span class="err"&gt;80007&lt;/span&gt;&lt;span class="nb"&gt;f8&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;   &lt;span class="mi"&gt;08001489&lt;/span&gt;    &lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;word&lt;/span&gt;   &lt;span class="mh"&gt;0x08001489&lt;/span&gt;
 &lt;span class="err"&gt;80007&lt;/span&gt;&lt;span class="nb"&gt;fc&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;   &lt;span class="mi"&gt;20000084&lt;/span&gt;    &lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;word&lt;/span&gt;   &lt;span class="mh"&gt;0x20000084&lt;/span&gt;

&lt;span class="err"&gt;(...)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, you see the &lt;em&gt;main()&lt;/em&gt; function in &lt;em&gt;.text&lt;/em&gt; section of the firmware. At left, the address of the machine code were being displayed. At center, you see the machine code corresponding to assembly instructions that is at right side.&lt;/p&gt;

&lt;p&gt;Inspecting the contents of ELF executable is huge topic. It has many variants and view-of-points in there.&lt;/p&gt;

&lt;p&gt;"Flashing" term means writing the dedicated sections of the firmware into the flash memory area of the microcontroller. It's done with many different ways. But I will show you openocd tool.&lt;/p&gt;

&lt;p&gt;In here, I have to define that how exactly does openocd work. It actually creates a server into the host machine with given configuration files. After starting the server session, you need to connect to that server over telnet or gdb. &lt;/p&gt;

&lt;p&gt;Let's do it. Firstly, connect the microcontroller to the host machine. Then open a terminal session and type this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;openocd &lt;span class="nt"&gt;-f&lt;/span&gt; interface/stlink.cfg &lt;span class="nt"&gt;-f&lt;/span&gt; target/stm32f4x.cfg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In here, I gave the two configuration files. First is the interface. As I said, I use the ST-Link connection. Second is the target file. It defines the target architecture. The openocd comes a bunch of configuration files. So search it and find the appropriate configuration files.&lt;/p&gt;

&lt;p&gt;You will see something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;Open On-Chip Debugger 0.12.0
Licensed under GNU GPL v2
For bug reports, read
    http://openocd.org/doc/doxygen/bugs.html
&lt;/span&gt;&lt;span class="gp"&gt;Info : auto-selecting first available session transport "hla_swd". To override use 'transport select &amp;lt;transport&amp;gt;&lt;/span&gt;&lt;span class="s1"&gt;'.
&lt;/span&gt;&lt;span class="go"&gt;Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : clock speed 2000 kHz
Info : STLINK V2J33M25 (API v2) VID:PID 0483:374B
Info : Target voltage: 3.224656
Info : [stm32f4x.cpu] Cortex-M4 r0p1 processor detected
Info : [stm32f4x.cpu] target has 6 breakpoints, 4 watchpoints
Info : starting gdb server for stm32f4x.cpu on 3333
Info : Listening on port 3333 for gdb connections
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The openocd attached the 4444 port to telnet and 3333 port to gdb. So that I will bind the 3333 port in the gdb session.&lt;/p&gt;

&lt;p&gt;Secondly, open the second terminal and type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;gdb-multiarch firmware.elf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At the moment, you are in the gdb session. In here, bind to the 3333 port:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;(gdb) target remote localhost:3333
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For now, you are in the control and responsible for the all flashing and debugging operations.&lt;/p&gt;

&lt;p&gt;To flash the firmware, use these commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;(gdb) monitor reset halt
(gdb) load
(gdb) monitor reset halt
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are tons of commands you can type in the gdb session. We can split these commands in two categories. &lt;em&gt;monitor &lt;/em&gt; commands directly are run by the openocd command. Other commands are run by the gdb itself.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;load&lt;/em&gt; is the main command to flash the firmware. Before and after that command, resetting and halting the CPU execution is good practice. Output will be like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Loading section .isr_vector, size 0x1c4 lma 0x8000000
Loading section .text, size 0x126c lma 0x8000200
Loading section .rodata, size 0x4c lma 0x800146c
Loading section .ARM, size 0x8 lma 0x80014b8
Loading section .init_array, size 0x4 lma 0x80014c0
Loading section .fini_array, size 0x4 lma 0x80014c4
Loading section .data, size 0xc lma 0x80014c8
Start address 0x08001400, load size 5272
Transfer rate: 9 KB/sec, 753 bytes/write.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That means that the firmware successfully was flashed 🥳.&lt;/p&gt;

&lt;p&gt;If you just wanna flash the firmware and not debugging, this following command is enough:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;openocd &lt;span class="nt"&gt;-f&lt;/span&gt; interface/stlink.cfg &lt;span class="nt"&gt;-f&lt;/span&gt; target/stm32f4x.cfg &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"program firmware.elf verify reset exit"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of dealing with two terminal sessions, above command is just the one-step operation.&lt;/p&gt;

&lt;p&gt;The main reason opening the second gdb session is to make the debugging. If you did the debugging previously, you will be familiar with these commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;(gdb) break main
(gdb) continue
(gdb) next
(gdb) finish
(gdb) print var
(gdb) x/16wx *ptr
(gdb) set var
(gdb) list
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The debugging operations are huge and will not fit into a single tutorial as you guest. So that I don't wanna dive into the these and other operations. But I wanna give you a good reference: &lt;em&gt;The Art of Debugging with GDB, DDD, and Eclipse&lt;/em&gt; written by Norman Matloff and Peter Jay Salzman.&lt;/p&gt;

&lt;p&gt;Until here, I gave a overall explanation the end-to-end pipeline. I'll explain the other stuffs in further. &lt;/p&gt;

</description>
      <category>lowcode</category>
      <category>c</category>
      <category>linux</category>
      <category>computerscience</category>
    </item>
    <item>
      <title>Simple Code Injection into ELF Executable</title>
      <dc:creator>Can Gulmez</dc:creator>
      <pubDate>Tue, 03 Mar 2026 12:44:18 +0000</pubDate>
      <link>https://dev.to/cangulmez/simple-code-injection-into-elf-executable-2i2o</link>
      <guid>https://dev.to/cangulmez/simple-code-injection-into-elf-executable-2i2o</guid>
      <description>&lt;p&gt;In this tutorial, I will explain an code injection technique into ELF executable.&lt;/p&gt;

&lt;p&gt;Firstly, you need to understand the ELF executable, its contents, sections, symbol table or so on. I've written a dedicated article previously. So if you don't have any information about ELF, please read it firstly and then come here again.&lt;/p&gt;

&lt;p&gt;Let's say we have the following source file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Simple Code Injection
 */&lt;/span&gt;

&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"#%d&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;EXIT_SUCCESS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compile this source file and then run it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;gcc main.c &lt;span class="nt"&gt;-o&lt;/span&gt; main &lt;span class="p"&gt;;&lt;/span&gt; ./main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, you will see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#0
#1
#2
#3
#4
#5
#6
#7
#8
#9
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In here, I will change the &lt;em&gt;num = 10&lt;/em&gt; to &lt;em&gt;num = 5&lt;/em&gt; so that the output will be #0 to #4. &lt;/p&gt;

&lt;p&gt;To accomplish this, I need to find the corresponding machine instruction/s. According to your background, you need to know that &lt;em&gt;num&lt;/em&gt; variable will be in the &lt;em&gt;.text&lt;/em&gt; section of ELF executable. Because it is the local variable. To display the .text section of the program, &lt;em&gt;objdump&lt;/em&gt; is the primarily tool:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;objdump &lt;span class="nt"&gt;-j&lt;/span&gt; .text &lt;span class="nt"&gt;-d&lt;/span&gt; main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output will be as following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nasm"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="err"&gt;0000000000001149&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="err"&gt;1149&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="nf"&gt;f3&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt; &lt;span class="nv"&gt;fa&lt;/span&gt;             &lt;span class="nv"&gt;endbr64&lt;/span&gt;
    &lt;span class="err"&gt;114&lt;/span&gt;&lt;span class="nl"&gt;d:&lt;/span&gt;   &lt;span class="err"&gt;55&lt;/span&gt;                      &lt;span class="nf"&gt;push&lt;/span&gt;   &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nb"&gt;rbp&lt;/span&gt;
    &lt;span class="err"&gt;114&lt;/span&gt;&lt;span class="nl"&gt;e:&lt;/span&gt;   &lt;span class="err"&gt;48&lt;/span&gt; &lt;span class="err"&gt;89&lt;/span&gt; &lt;span class="nf"&gt;e5&lt;/span&gt;                &lt;span class="nv"&gt;mov&lt;/span&gt;    &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nb"&gt;rsp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nb"&gt;rbp&lt;/span&gt;
    &lt;span class="err"&gt;1151&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="err"&gt;48&lt;/span&gt; &lt;span class="err"&gt;83&lt;/span&gt; &lt;span class="nf"&gt;ec&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;             &lt;span class="nv"&gt;sub&lt;/span&gt;    &lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mh"&gt;0x20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nb"&gt;rsp&lt;/span&gt;
    &lt;span class="err"&gt;1155&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="err"&gt;89&lt;/span&gt; &lt;span class="err"&gt;7&lt;/span&gt;&lt;span class="nf"&gt;d&lt;/span&gt; &lt;span class="nv"&gt;ec&lt;/span&gt;                &lt;span class="nv"&gt;mov&lt;/span&gt;    &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nb"&gt;edi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mh"&gt;0x14&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nb"&gt;rbp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="err"&gt;1158&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="err"&gt;48&lt;/span&gt; &lt;span class="err"&gt;89&lt;/span&gt; &lt;span class="err"&gt;75&lt;/span&gt; &lt;span class="nf"&gt;e0&lt;/span&gt;             &lt;span class="nv"&gt;mov&lt;/span&gt;    &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nb"&gt;rsi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mh"&gt;0x20&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nb"&gt;rbp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="err"&gt;115&lt;/span&gt;&lt;span class="nl"&gt;c:&lt;/span&gt;   &lt;span class="nf"&gt;c7&lt;/span&gt; &lt;span class="mi"&gt;45&lt;/span&gt; &lt;span class="nv"&gt;fc&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt;    &lt;span class="nv"&gt;movl&lt;/span&gt;   &lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mh"&gt;0xa&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mh"&gt;0x4&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nb"&gt;rbp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="err"&gt;1163&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="nf"&gt;c7&lt;/span&gt; &lt;span class="mi"&gt;45&lt;/span&gt; &lt;span class="nv"&gt;f8&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt;    &lt;span class="nv"&gt;movl&lt;/span&gt;   &lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mh"&gt;0x0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mh"&gt;0x8&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nb"&gt;rbp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="err"&gt;116&lt;/span&gt;&lt;span class="nl"&gt;a:&lt;/span&gt;   &lt;span class="nf"&gt;eb&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt;                   &lt;span class="nv"&gt;jmp&lt;/span&gt;    &lt;span class="mi"&gt;1189&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mh"&gt;0x40&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="err"&gt;116&lt;/span&gt;&lt;span class="nl"&gt;c:&lt;/span&gt;   &lt;span class="err"&gt;8&lt;/span&gt;&lt;span class="nf"&gt;b&lt;/span&gt; &lt;span class="mi"&gt;45&lt;/span&gt; &lt;span class="nv"&gt;f8&lt;/span&gt;                &lt;span class="nv"&gt;mov&lt;/span&gt;    &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mh"&gt;0x8&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nb"&gt;rbp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nb"&gt;eax&lt;/span&gt;
    &lt;span class="err"&gt;116&lt;/span&gt;&lt;span class="nl"&gt;f:&lt;/span&gt;   &lt;span class="err"&gt;89&lt;/span&gt; &lt;span class="nf"&gt;c6&lt;/span&gt;                   &lt;span class="nv"&gt;mov&lt;/span&gt;    &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nb"&gt;eax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nb"&gt;esi&lt;/span&gt;
    &lt;span class="err"&gt;1171&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="err"&gt;48&lt;/span&gt; &lt;span class="err"&gt;8&lt;/span&gt;&lt;span class="nf"&gt;d&lt;/span&gt; &lt;span class="mi"&gt;05&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt;    &lt;span class="nv"&gt;lea&lt;/span&gt;    &lt;span class="mh"&gt;0xe8c&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nv"&gt;rip&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nb"&gt;rax&lt;/span&gt;        &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="mi"&gt;2004&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;_IO_stdin_used&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mh"&gt;0x4&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="err"&gt;1178&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="err"&gt;48&lt;/span&gt; &lt;span class="err"&gt;89&lt;/span&gt; &lt;span class="nf"&gt;c7&lt;/span&gt;                &lt;span class="nv"&gt;mov&lt;/span&gt;    &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nb"&gt;rax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nb"&gt;rdi&lt;/span&gt;
    &lt;span class="err"&gt;117&lt;/span&gt;&lt;span class="nl"&gt;b:&lt;/span&gt;   &lt;span class="nf"&gt;b8&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt;          &lt;span class="nv"&gt;mov&lt;/span&gt;    &lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mh"&gt;0x0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nb"&gt;eax&lt;/span&gt;
    &lt;span class="err"&gt;1180&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="nf"&gt;e8&lt;/span&gt; &lt;span class="nv"&gt;cb&lt;/span&gt; &lt;span class="nv"&gt;fe&lt;/span&gt; &lt;span class="nv"&gt;ff&lt;/span&gt; &lt;span class="nv"&gt;ff&lt;/span&gt;          &lt;span class="nv"&gt;call&lt;/span&gt;   &lt;span class="mi"&gt;1050&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;printf@plt&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="err"&gt;1185&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="err"&gt;83&lt;/span&gt; &lt;span class="err"&gt;45&lt;/span&gt; &lt;span class="nf"&gt;f8&lt;/span&gt; &lt;span class="mi"&gt;01&lt;/span&gt;             &lt;span class="nv"&gt;addl&lt;/span&gt;   &lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mh"&gt;0x1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mh"&gt;0x8&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nb"&gt;rbp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="err"&gt;1189&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="err"&gt;8&lt;/span&gt;&lt;span class="nf"&gt;b&lt;/span&gt; &lt;span class="mi"&gt;45&lt;/span&gt; &lt;span class="nv"&gt;f8&lt;/span&gt;                &lt;span class="nv"&gt;mov&lt;/span&gt;    &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mh"&gt;0x8&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nb"&gt;rbp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nb"&gt;eax&lt;/span&gt;
    &lt;span class="err"&gt;118&lt;/span&gt;&lt;span class="nl"&gt;c:&lt;/span&gt;   &lt;span class="err"&gt;3&lt;/span&gt;&lt;span class="nf"&gt;b&lt;/span&gt; &lt;span class="mi"&gt;45&lt;/span&gt; &lt;span class="nv"&gt;fc&lt;/span&gt;                &lt;span class="nv"&gt;cmp&lt;/span&gt;    &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mh"&gt;0x4&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nb"&gt;rbp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nb"&gt;eax&lt;/span&gt;
    &lt;span class="err"&gt;118&lt;/span&gt;&lt;span class="nl"&gt;f:&lt;/span&gt;   &lt;span class="err"&gt;7&lt;/span&gt;&lt;span class="nf"&gt;c&lt;/span&gt; &lt;span class="nv"&gt;db&lt;/span&gt;                   &lt;span class="nv"&gt;jl&lt;/span&gt;     &lt;span class="mi"&gt;116&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mh"&gt;0x23&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="err"&gt;1191&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="nf"&gt;b8&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt;          &lt;span class="nv"&gt;mov&lt;/span&gt;    &lt;span class="kc"&gt;$&lt;/span&gt;&lt;span class="mh"&gt;0x0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nb"&gt;eax&lt;/span&gt;
    &lt;span class="err"&gt;1196&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="nf"&gt;c9&lt;/span&gt;                      &lt;span class="nv"&gt;leave&lt;/span&gt;
    &lt;span class="err"&gt;1197&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="nf"&gt;c3&lt;/span&gt;                      &lt;span class="nv"&gt;ret&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which machine instruction/s corresponds to &lt;em&gt;num = 10&lt;/em&gt;? You need to know reading the assembly instructions in here. The answer is the &lt;strong&gt;movl   $0xa,-0x4(%rbp)&lt;/strong&gt; assembly instruction. Because the stack pointer of the program was enlarged by 4 bytes (&lt;em&gt;int&lt;/em&gt; holds 4 bytes of memory) to lower address and put the immediate 0xA value. So that I need to change the 0xA value to 0x5. &lt;/p&gt;

&lt;p&gt;After the found required assembly instruction, I need to determine the memory address of it. If you look at center column, the machine instruction is &lt;strong&gt;c7 45 fc 0a 00 00 00&lt;/strong&gt;. In here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;c7: the opcode of &lt;em&gt;movl&lt;/em&gt; register&lt;/li&gt;
&lt;li&gt;45 fc: the displacement of -0x4(%rbp)&lt;/li&gt;
&lt;li&gt;0a 00 00 00: the immediate value, 0xA (little-endian)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;c7 byte resides at 0x115c address so that 0a byte at 0x115f.&lt;/p&gt;

&lt;p&gt;To change that byte, I'm gonna use &lt;em&gt;hexedit&lt;/em&gt; program:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;hexedit ./main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will see:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6xykdj3162c4xy1fq0pv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6xykdj3162c4xy1fq0pv.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After that, you move to 0x115F address and change the 0x0A value to 0x05. Save the changes and then run the program again. You will see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#0
#1
#2
#3
#4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. You injected the new code in the ELF executable 🥳. &lt;/p&gt;

&lt;p&gt;This technique is simple and powerful. But there are some limitations. The most important one is that you should not shift the byte addresses, just replace it. If you wanna change the entire ELF executable addresses, you need the other techniques. That's the next article's topic.&lt;/p&gt;

</description>
      <category>c</category>
      <category>lowcode</category>
      <category>computerscience</category>
      <category>linux</category>
    </item>
    <item>
      <title>ELF Executable Analysis in Detail</title>
      <dc:creator>Can Gulmez</dc:creator>
      <pubDate>Tue, 24 Feb 2026 20:03:28 +0000</pubDate>
      <link>https://dev.to/cangulmez/elf-executable-analysis-in-detail-3p5i</link>
      <guid>https://dev.to/cangulmez/elf-executable-analysis-in-detail-3p5i</guid>
      <description>&lt;p&gt;In everyday, we run some kind of programs to handle our works. There are many type of programs, GUIs, CLIs, TUIs or so on. But at low level, there are two kind of program formats: PE (Portable Executable) for Windows and ELF (Executable and Linkable Format) for Linux. &lt;/p&gt;

&lt;p&gt;In this tutorial, I will explain the ELF executables in detail.&lt;/p&gt;

&lt;p&gt;Firstly, let's start with the overall layout:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcpujvtc64w38ocjvh6zc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcpujvtc64w38ocjvh6zc.png" alt=" " width="387" height="616"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you see, an ELF executable consists of four layers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Executable Header&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Program Headers&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sections&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Section Headers&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Executable Header
&lt;/h3&gt;

&lt;p&gt;Every ELF file starts with an &lt;em&gt;executable header&lt;/em&gt;, which is just a structured series of bytes telling you that it's an ELF file, what kind of ELF file it is, and where in the file to find all the other contents. It's defined as follow in /usr/include/elf.h:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdurlu5pmfkinz7utvied.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdurlu5pmfkinz7utvied.png" alt=" " width="589" height="367"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;e_ident&lt;/em&gt;: The executable header starts with a 16-byte array. First 4-byte, magic value, identifying the file as an ELF binary.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;e_type&lt;/em&gt;: The type of the executable. For example REL means relocatable object file, EXEC means executable binary and DYN means dynamic libraries.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;e_machine&lt;/em&gt;: The architecture that the executable is intended to run on.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;e_version&lt;/em&gt;: The version of the ELF specification (always 1, I really don't know why it exists 😂).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;e_entry&lt;/em&gt;: The virtual address at which execution should start.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;e_phoff&lt;/em&gt;, &lt;em&gt;e_shoff&lt;/em&gt;: The file offsets to the beginning of the program header table and the section header table.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;e_flags&lt;/em&gt;: The flags specific to the architecture for which the binary is compiled (typically 0 for x86_64).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;e_ehsize&lt;/em&gt;: The size of the executable header, in bytes (for 64-bit systems, it's always 64).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can see the executable header with this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ readelf -h ./prog
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              DYN (Position-Independent Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x1400
  Start of program headers:          64 (bytes into file)
  Start of section headers:          135496 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         13
  Size of section headers:           64 (bytes)
  Number of section headers:         29
  Section header string table index: 28
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Section Headers
&lt;/h3&gt;

&lt;p&gt;The code and data in an ELF binary are logically divided into continuous nonoverlapping chunks called &lt;strong&gt;section&lt;/strong&gt;s. Sections don't have any predetermined structure; instead, the structure of each section varies depending on the contents. So every section is described in &lt;em&gt;section header table&lt;/em&gt;. It's defined as follow:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgrorlbmbp2grio4ulyfa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgrorlbmbp2grio4ulyfa.png" alt=" " width="582" height="277"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;sh_name&lt;/em&gt;: The index of the sections.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;sh_type&lt;/em&gt;: Every section has a type, indicated by an integer field. Common types: PROBITS for machine instructions, SYMTAB for static symbol table, DYNSYM for dynamic symbol table, STRTAB for string tables, REL(A) for relocation entries used by the linker, DYNAMIC for information needed for dynamic linking or so on.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;sh_flags&lt;/em&gt;: The section flags. Common flags: W means the section is writable, A means the content of the section are to be loaded into memory when executing the executable, X means the section is executable.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;sh_addr, sh_offset, sh_size&lt;/em&gt;: The virtual address, file offset (in bytes from the start&lt;br&gt;
of the file), and size (in bytes) of the sections.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;sh_link&lt;/em&gt;: Sometimes, there are relationships between sections. This field keeps the index count of the related sections.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;sh_info&lt;/em&gt;: Additional information about sections.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;sh_addralign&lt;/em&gt;: Some sections may need to be aligned in memory in a particular way for efficiency of memory accesses. The values 0 and 1 are reserved to indicate no special alignment needs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;sh_entsize&lt;/em&gt;: Some sections contain a table of well-defined data structures. For such sections, this field indicates the size in bytes of each entry in the table. When the field is unused, it is set to zero.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can see the section headers with this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ readelf --sections --wide ./prog
There are 29 section headers, starting at offset 0x21148:

Section Headers:
  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
  [ 1] .interp           PROGBITS        0000000000000318 000318 00001c 00   A  0   0  1
  [ 2] .note.gnu.property NOTE            0000000000000338 000338 000030 00   A  0   0  8
  [ 3] .note.gnu.build-id NOTE            0000000000000368 000368 000024 00   A  0   0  4
  [ 4] .note.ABI-tag     NOTE            000000000000038c 00038c 000020 00   A  0   0  4
  [ 5] .gnu.hash         GNU_HASH        00000000000003b0 0003b0 000028 00   A  6   0  8
  [ 6] .dynsym           DYNSYM          00000000000003d8 0003d8 000378 18   A  7   1  8
  [ 7] .dynstr           STRTAB          0000000000000750 000750 00016d 00   A  0   0  1
  [ 8] .gnu.version      VERSYM          00000000000008be 0008be 00004a 02   A  6   0  2
  [ 9] .gnu.version_r    VERNEED         0000000000000908 000908 000080 00   A  7   2  8
  [10] .rela.dyn         RELA            0000000000000988 000988 0000d8 18   A  6   0  8
  [11] .rela.plt         RELA            0000000000000a60 000a60 0002d0 18  AI  6  24  8
  [12] .init             PROGBITS        0000000000001000 001000 00001b 00  AX  0   0  4
  [13] .plt              PROGBITS        0000000000001020 001020 0001f0 10  AX  0   0 16
  [14] .plt.got          PROGBITS        0000000000001210 001210 000010 10  AX  0   0 16
  [15] .plt.sec          PROGBITS        0000000000001220 001220 0001e0 10  AX  0   0 16
  [16] .text             PROGBITS        0000000000001400 001400 018c54 00  AX  0   0 16
  [17] .fini             PROGBITS        000000000001a054 01a054 00000d 00  AX  0   0  4
  [18] .rodata           PROGBITS        000000000001b000 01b000 002ee8 00   A  0   0 16
  [19] .eh_frame_hdr     PROGBITS        000000000001dee8 01dee8 0005fc 00   A  0   0  4
  [20] .eh_frame         PROGBITS        000000000001e4e8 01e4e8 001914 00   A  0   0  8
  [21] .init_array       INIT_ARRAY      0000000000020cc0 020cc0 000008 08  WA  0   0  8
  [22] .fini_array       FINI_ARRAY      0000000000020cc8 020cc8 000008 08  WA  0   0  8
  [23] .dynamic          DYNAMIC         0000000000020cd0 020cd0 000200 10  WA  7   0  8
  [24] .got              PROGBITS        0000000000020ed0 020ed0 000130 08  WA  0   0  8
  [25] .data             PROGBITS        0000000000021000 021000 000010 00  WA  0   0  8
  [26] .bss              NOBITS          0000000000021020 021010 000010 00  WA  0   0 32
  [27] .comment          PROGBITS        0000000000000000 021010 00002b 01  MS  0   0  1
  [28] .shstrtab         STRTAB          0000000000000000 02103b 00010a 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  D (mbind), l (large), p (processor specific)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Sections
&lt;/h3&gt;

&lt;p&gt;In previous chapter, you see that the ELF executable has a set of sections at which each section has a special meaning. For now, let me explain these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;.init and .fini&lt;/em&gt;: The &lt;em&gt;.init&lt;/em&gt; section contains machine code that performs initialization before the &lt;em&gt;main()&lt;/em&gt; function and &lt;em&gt;.fini&lt;/em&gt; runs after it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;.text&lt;/em&gt;: This section is where the main code of the executable resides that we've wrote. It's the main concern for binary analysis or reverse engineering efforts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;.bss, .data, .rodata&lt;/em&gt;: There sections are where the program variables live. According to the declaration style, the variable goes into one of the three sections. For example, &lt;em&gt;initialized&lt;/em&gt; global variables live in &lt;em&gt;.data&lt;/em&gt;, &lt;em&gt;uninitialized&lt;/em&gt; global variables live in &lt;em&gt;.bss&lt;/em&gt; and &lt;em&gt;constant&lt;/em&gt; variables live in &lt;em&gt;.rodata&lt;/em&gt;. Don't forget that the local variables go in the stack, so &lt;em&gt;.text&lt;/em&gt;, not into one of these sections.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;.rel.* and .rela.*&lt;/em&gt;: These sections contain the information used by the linker for performing relocations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;.dynamic&lt;/em&gt;: It contains the "road map" for dynamic linker when loading and setting up the ELF executable.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As an example, you can inspect a specific section with this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ objdump -j .text -d ./prog

./prog:     file format elf64-x86-64

Disassembly of section .text:

0000000000001400 &amp;lt;.text&amp;gt;:
    1400:       f3 0f 1e fa             endbr64
    1404:       31 ed                   xor    %ebp,%ebp
    1406:       49 89 d1                mov    %rdx,%r9
    1409:       5e                      pop    %rsi
    140a:       48 89 e2                mov    %rsp,%rdx
    140d:       48 83 e4 f0             and    $0xfffffffffffffff0,%rsp
    1411:       50                      push   %rax
    1412:       54                      push   %rsp
    1413:       45 31 c0                xor    %r8d,%r8d
    1416:       31 c9                   xor    %ecx,%ecx
    1418:       48 8d 3d 48 15 00 00    lea    0x1548(%rip),%rdi        # 2967 &amp;lt;rand@plt+0x1577&amp;gt;
    141f:       ff 15 b3 fb 01 00       call   *0x1fbb3(%rip)        # 20fd8 &amp;lt;rand@plt+0x1fbe8&amp;gt;
    1425:       f4                      hlt
    1426:       66 2e 0f 1f 84 00 00    cs nopw 0x0(%rax,%rax,1)
    142d:       00 00 00 
    1430:       48 8d 3d d9 fb 01 00    lea    0x1fbd9(%rip),%rdi        # 21010 &amp;lt;rand@plt+0x1fc20&amp;gt;
    1437:       48 8d 05 d2 fb 01 00    lea    0x1fbd2(%rip),%rax        # 21010 &amp;lt;rand@plt+0x1fc20&amp;gt;
    143e:       48 39 f8                cmp    %rdi,%rax
    1441:       74 15                   je     1458 &amp;lt;rand@plt+0x68&amp;gt;
    1443:       48 8b 05 96 fb 01 00    mov    0x1fb96(%rip),%rax        # 20fe0 &amp;lt;rand@plt+0x1fbf0&amp;gt;
    144a:       48 85 c0                test   %rax,%rax
    144d:       74 09                   je     1458 &amp;lt;rand@plt+0x68&amp;gt;
    144f:       ff e0                   jmp    *%rax
    1451:       0f 1f 80 00 00 00 00    nopl   0x0(%rax)

(...)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Program Headers
&lt;/h3&gt;

&lt;p&gt;The program header table provides a &lt;em&gt;segment view&lt;/em&gt; of the binary, as opposed to the &lt;em&gt;section view&lt;/em&gt; provided by the section header table. It's defined as follow:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg8ju6auuns4gk64up863.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg8ju6auuns4gk64up863.png" alt=" " width="453" height="118"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4azsq1vx1s8vi1bos53x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4azsq1vx1s8vi1bos53x.png" alt=" " width="453" height="113"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;p_type&lt;/em&gt;: The type of segments. Common types: LOAD means the segment are intended to be loaded into memory, INTERP means the segment contains &lt;em&gt;.interp&lt;/em&gt; section providing name of the interpreter that is to be used to load the executable, DYNAMIC means the segment contains the &lt;em&gt;.dynamic&lt;/em&gt; section, which tells the interpreter how to parse and prepare the binary for execution, PHDR means the segment encompasses the program header table.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;p_flags&lt;/em&gt;: The runtime access permissions for the segments. Common flags: X means executable, R means readable, W means writable or so on.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;p_offset, p_vaddr, p_paddr, p_filesz, p_memsz&lt;/em&gt;: These equals to &lt;em&gt;sh_offset&lt;/em&gt;, &lt;em&gt;sh_addr&lt;/em&gt;, &lt;em&gt;sh_size&lt;/em&gt; fields in the section headers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;p_align&lt;/em&gt;: It's equal to &lt;em&gt;sh_addralign&lt;/em&gt; field.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can see the program headers with this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ readelf --segments --wide ./prog

Elf file type is DYN (Position-Independent Executable file)
Entry point 0x1400
There are 13 program headers, starting at offset 64

Program Headers:
  Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
  PHDR           0x000040 0x0000000000000040 0x0000000000000040 0x0002d8 0x0002d8 R   0x8
  INTERP         0x000318 0x0000000000000318 0x0000000000000318 0x00001c 0x00001c R   0x1
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD           0x000000 0x0000000000000000 0x0000000000000000 0x000d30 0x000d30 R   0x1000
  LOAD           0x001000 0x0000000000001000 0x0000000000001000 0x019061 0x019061 R E 0x1000
  LOAD           0x01b000 0x000000000001b000 0x000000000001b000 0x004dfc 0x004dfc R   0x1000
  LOAD           0x020cc0 0x0000000000020cc0 0x0000000000020cc0 0x000350 0x000370 RW  0x1000
  DYNAMIC        0x020cd0 0x0000000000020cd0 0x0000000000020cd0 0x000200 0x000200 RW  0x8
  NOTE           0x000338 0x0000000000000338 0x0000000000000338 0x000030 0x000030 R   0x8
  NOTE           0x000368 0x0000000000000368 0x0000000000000368 0x000044 0x000044 R   0x4
  GNU_PROPERTY   0x000338 0x0000000000000338 0x0000000000000338 0x000030 0x000030 R   0x8
  GNU_EH_FRAME   0x01dee8 0x000000000001dee8 0x000000000001dee8 0x0005fc 0x0005fc R   0x4
  GNU_STACK      0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW  0x10
  GNU_RELRO      0x020cc0 0x0000000000020cc0 0x0000000000020cc0 0x000340 0x000340 R   0x1

 Section to Segment mapping:
  Segment Sections...
   00     
   01     .interp 
   02     .interp .note.gnu.property .note.gnu.build-id .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt 
   03     .init .plt .plt.got .plt.sec .text .fini 
   04     .rodata .eh_frame_hdr .eh_frame 
   05     .init_array .fini_array .dynamic .got .data .bss 
   06     .dynamic 
   07     .note.gnu.property 
   08     .note.gnu.build-id .note.ABI-tag 
   09     .note.gnu.property 
   10     .eh_frame_hdr 
   11     
   12     .init_array .fini_array .dynamic .got 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Until here, I gave you the overall, a bit detailed, presentation about the ELF executable. For next articles, I will dive into the binary analysis techniques in deeply for Linux.&lt;/p&gt;

&lt;p&gt;Resource:&lt;/p&gt;

&lt;p&gt;Andriesse D., Practical Binary Analysis, no starch press, San Francisco.&lt;/p&gt;

</description>
      <category>c</category>
      <category>gcc</category>
      <category>lowcode</category>
      <category>computerscience</category>
    </item>
    <item>
      <title>How to build a firmware using Makefile?</title>
      <dc:creator>Can Gulmez</dc:creator>
      <pubDate>Sun, 21 Dec 2025 12:46:38 +0000</pubDate>
      <link>https://dev.to/cangulmez/how-to-build-a-firmware-using-makefile-3flm</link>
      <guid>https://dev.to/cangulmez/how-to-build-a-firmware-using-makefile-3flm</guid>
      <description>&lt;p&gt;In embedded programming, we trust IDEs like STM32CubeIDE, Keil or so on. These IDEs give us just some buttons and UIs to build, flash, and debug the source code that we've written for a MCU. But, I think that every engineer that works on this field have to know that how these steps are made by hand.&lt;/p&gt;

&lt;p&gt;In this tutorial, I will show building a firmware written for STM32F446RE MCU with just using a single Makefile.&lt;/p&gt;

&lt;p&gt;Below is the project directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ tree
.
├── bin/
├── drivers/
│&amp;nbsp;&amp;nbsp; ├── CMSIS/
│&amp;nbsp;&amp;nbsp; ├── STM32F446RETX_FLASH.ld
│&amp;nbsp;&amp;nbsp; └── STM32F4xx_HAL_Driver/
├── lib/
├── Makefile
└── src/
    ├── it.c
    ├── main.c
    ├── main.h
    └── peripheral.c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Firstly, which libraries do we need to have?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;HAL library&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CMSIS library&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Linker script&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Startup/system code&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;arm-none-eabi-* tools&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I've put the all required libraries/scripts into &lt;strong&gt;/drivers&lt;/strong&gt; directory. Please download these using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;git clone &lt;span class="nt"&gt;--recurse-submodules&lt;/span&gt; https://github.com/STMicroelectronics/STM32CubeF4.git
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;gcc-arm-none-eabi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In here, HAL library is used to program the peripherals and CMSIS for ARM-Cortex itself. These are the most important libraries that we have to get. &lt;/p&gt;

&lt;p&gt;Apart from that, we also need some special files. First is the &lt;strong&gt;linker script&lt;/strong&gt;. It includes the memory layout of microcontroller. Sometimes, it comes from above command. But if you cannot find it there, please install it externally. Another file is the &lt;strong&gt;startup code&lt;/strong&gt;. It's written in Assembly language. As its name suggests, it's the first code that runs in microcontroller. Basically, it includes the &lt;strong&gt;Reset_Handler&lt;/strong&gt; and a branch that jumps into &lt;strong&gt;main()&lt;/strong&gt; function in your source code. Also &lt;strong&gt;system code&lt;/strong&gt; includes the some generic and general definitions.&lt;/p&gt;

&lt;p&gt;After downloaded and explained the required ones, Let's write the &lt;strong&gt;Makefile&lt;/strong&gt; step by step:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Toolchain definitions&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;CC&lt;/span&gt;              &lt;span class="o"&gt;:=&lt;/span&gt; arm-none-eabi-gcc
&lt;span class="nv"&gt;OBJCOPY&lt;/span&gt;         &lt;span class="o"&gt;:=&lt;/span&gt; arm-none-eabi-objcopy
&lt;span class="nv"&gt;SIZE&lt;/span&gt;            &lt;span class="o"&gt;:=&lt;/span&gt; arm-none-eabi-size
&lt;span class="nv"&gt;RM&lt;/span&gt;              &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt;
&lt;span class="nv"&gt;FILE&lt;/span&gt;            &lt;span class="o"&gt;:=&lt;/span&gt; file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. MCU-specific definitions&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;DEVICE_FAMILY&lt;/span&gt;        &lt;span class="o"&gt;:=&lt;/span&gt; STM32F4xx
&lt;span class="nv"&gt;DEVICE_MODEL&lt;/span&gt;         &lt;span class="o"&gt;:=&lt;/span&gt; STM32F446xx
&lt;span class="nv"&gt;DEVICE_VARIANT&lt;/span&gt;       &lt;span class="o"&gt;:=&lt;/span&gt; STM32F446RETx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Compiler and linker flags&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;CORTEX_FLAGS&lt;/span&gt;         &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nt"&gt;-mthumb&lt;/span&gt; &lt;span class="nt"&gt;-mcpu&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;cortex-m4 &lt;span class="nt"&gt;-mfpu&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;fpv4-sp-d16 &lt;span class="nt"&gt;-mfloat-abi&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;hard
&lt;span class="nv"&gt;COMMON_FLAGS&lt;/span&gt;         &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nt"&gt;-g3&lt;/span&gt; &lt;span class="nt"&gt;-Os&lt;/span&gt; &lt;span class="nt"&gt;-ffunction-sections&lt;/span&gt; &lt;span class="nt"&gt;-fdata-sections&lt;/span&gt; &lt;span class="nt"&gt;-Wall&lt;/span&gt;
&lt;span class="nv"&gt;AS_FLAGS&lt;/span&gt;             &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nt"&gt;-x&lt;/span&gt; assembler-with-cpp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In here, we've defined some flags:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;-mthumb&lt;/strong&gt; means that the firmware uses thumb (16-bit) instruction set.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;-mcpu=cortex-m4&lt;/strong&gt; means the ARM-Cortex series itself.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;-mfpu=fpv4-sp-d16&lt;/strong&gt; and &lt;strong&gt;-mfloat-abi=hard&lt;/strong&gt; means that floating-point operations can be done in the firmware.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;4. Include paths&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;MAIN_INC&lt;/span&gt;        &lt;span class="o"&gt;:=&lt;/span&gt; ./src
&lt;span class="nv"&gt;CMSIS_INC&lt;/span&gt;       &lt;span class="o"&gt;:=&lt;/span&gt; ./drivers/CMSIS/Include
&lt;span class="nv"&gt;CMSIS_DEV_INC&lt;/span&gt;   &lt;span class="o"&gt;:=&lt;/span&gt; ./drivers/CMSIS/Device/ST/STM32F4xx/Include
&lt;span class="nv"&gt;HAL_INC&lt;/span&gt;         &lt;span class="o"&gt;:=&lt;/span&gt; ./drivers/STM32F4xx_HAL_Driver/Inc
&lt;span class="nv"&gt;CMSIS_DSP_INC&lt;/span&gt;   &lt;span class="o"&gt;:=&lt;/span&gt; ./drivers/CMSIS/DSP/Include
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In here, we specified the header files that are used in the source code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Source and special files&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;MAIN_SRC&lt;/span&gt;        &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;wildcard ./src/&lt;span class="k"&gt;*&lt;/span&gt;.c&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;HAL_SRC&lt;/span&gt;         &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;wildcard ./drivers/STM32F4xx_HAL_Driver/Src/&lt;span class="k"&gt;*&lt;/span&gt;.c&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;SYSTEM_SRC&lt;/span&gt;      &lt;span class="o"&gt;:=&lt;/span&gt; ./drivers/CMSIS/Device/ST/STM32F4xx/Source/Templates/system_stm32f4xx.c
&lt;span class="nv"&gt;STARTUP_CODE&lt;/span&gt;    &lt;span class="o"&gt;:=&lt;/span&gt; ./drivers/CMSIS/Device/ST/STM32F4xx/Source/Templates/gcc/startup_stm32f446xx.S
&lt;span class="nv"&gt;LINKER_SCRIPT&lt;/span&gt;   &lt;span class="o"&gt;:=&lt;/span&gt; ./drivers/STM32F446RETX_FLASH.ld
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;6. Sorthands and build definitions&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;DEFINES&lt;/span&gt;         &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nt"&gt;-D&lt;/span&gt;&lt;span class="p"&gt;$(&lt;/span&gt;DEVICE_FAMILY&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-D&lt;/span&gt;&lt;span class="p"&gt;$(&lt;/span&gt;DEVICE_MODEL&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-D&lt;/span&gt;&lt;span class="p"&gt;$(&lt;/span&gt;DEVICE_VARIANT&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
                        &lt;span class="nt"&gt;-DUSE_HAL_DRIVER&lt;/span&gt;

&lt;span class="nv"&gt;SOURCES&lt;/span&gt;         &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;MAIN_SRC&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;HAL_SRC&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;SYSTEM_SRC&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;OBJECTS&lt;/span&gt;         &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;notdir &lt;span class="p"&gt;$(&lt;/span&gt;patsubst %.c,%.o,&lt;span class="p"&gt;$(&lt;/span&gt;SOURCES&lt;span class="p"&gt;)))&lt;/span&gt; startup_stm32f446xx.o
&lt;span class="nv"&gt;INCLUDES&lt;/span&gt;            &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nt"&gt;-I&lt;/span&gt;&lt;span class="p"&gt;$(&lt;/span&gt;MAIN_INC&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-I&lt;/span&gt;&lt;span class="p"&gt;$(&lt;/span&gt;CMSIS_DEV_INC&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-I&lt;/span&gt;&lt;span class="p"&gt;$(&lt;/span&gt;CMSIS_INC&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-I&lt;/span&gt;&lt;span class="p"&gt;$(&lt;/span&gt;HAL_INC&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
                        &lt;span class="nt"&gt;-I&lt;/span&gt;&lt;span class="p"&gt;$(&lt;/span&gt;CMSIS_DSP_INC&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nv"&gt;CFLAGS&lt;/span&gt;          &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;CORTEX_FLAGS&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;COMMON_FLAGS&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;DEFINES&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;INCLUDES&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;AFLAGS&lt;/span&gt;          &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;CORTEX_FLAGS&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;AS_FLAGS&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;DEFINES&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;INCLUDES&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;LDFLAGS&lt;/span&gt;         &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;CORTEX_FLAGS&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-T&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;LINKER_SCRIPT&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
                        &lt;span class="nt"&gt;-Wl&lt;/span&gt;,--gc-sections,--relax &lt;span class="nt"&gt;--specs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nano.specs &lt;span class="nt"&gt;--specs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nosys.specs &lt;span class="se"&gt;\&lt;/span&gt;
                    &lt;span class="nt"&gt;-Wl&lt;/span&gt;,--start-group &lt;span class="nt"&gt;-lc&lt;/span&gt; &lt;span class="nt"&gt;-lm&lt;/span&gt; &lt;span class="nt"&gt;-lnosys&lt;/span&gt; &lt;span class="nt"&gt;-Wl&lt;/span&gt;,--end-group
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In here, I mostly did the string operations and manipulations. But some points are interesting and need some explanations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Firstly, I've grouped the sources and libraries and converted the source file suffixes into object file formats.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Also, I've created three total flags that will be used for compiling, assembling, and linking phases.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In linker flags, I put the linker script. As you noticed, this step will be done after the compiling the source files. I also linked the some libraries. &lt;strong&gt;-lc&lt;/strong&gt; is the standard C library. In firmware, we use often string manipulation functions (&lt;strong&gt;strlen()&lt;/strong&gt;, &lt;strong&gt;strcat()&lt;/strong&gt;, &lt;strong&gt;strcpy()&lt;/strong&gt; or so on), &lt;strong&gt;snprint()&lt;/strong&gt;, &lt;strong&gt;memset()&lt;/strong&gt;, or similar ones. &lt;strong&gt;-lm&lt;/strong&gt; is the math library as you know. &lt;strong&gt;-lnosys&lt;/strong&gt; means that I'm just implementing the bare-metal firmware, there is no such as kernel or fully OS.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;7. Output files&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;FIRMWARE_ELF&lt;/span&gt;    &lt;span class="o"&gt;:=&lt;/span&gt; firmware.elf
&lt;span class="nv"&gt;FIRMWARE_BIN&lt;/span&gt;    &lt;span class="o"&gt;:=&lt;/span&gt; firmware.bin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Generally, we use the ELF file when flashing and debugging. ELF executable includes the both machine code, metadata, debug information, symbol table or similar stuffs. In contrast, BIN executable just includes the machine code. If you look at the size of both, you will use the ELF executable is much bigger! &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8. The recipe&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;all&lt;/span&gt;

&lt;span class="nl"&gt;all&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"-------------------------------------"&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"----- Building the source files -----"&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"-------------------------------------"&lt;/span&gt;
    &lt;span class="p"&gt;@$(&lt;/span&gt;CC&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;AFLAGS&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;STARTUP_CODE&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;@$(&lt;/span&gt;CC&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;CFLAGS&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;SOURCES&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="err"&gt;@echo&lt;/span&gt; &lt;span class="s2"&gt;"\n------------------------------------"&lt;/span&gt;
    &lt;span class="err"&gt;@echo&lt;/span&gt; &lt;span class="s2"&gt;"----- Linking the object files -----"&lt;/span&gt;
    &lt;span class="err"&gt;@echo&lt;/span&gt; &lt;span class="s2"&gt;"------------------------------------"&lt;/span&gt;
    &lt;span class="err"&gt;@$(CC)&lt;/span&gt; &lt;span class="err"&gt;$(LDFLAGS)&lt;/span&gt; &lt;span class="err"&gt;$(OBJECTS)&lt;/span&gt; &lt;span class="err"&gt;-o&lt;/span&gt; &lt;span class="err"&gt;$(FIRMWARE_ELF)&lt;/span&gt;
    &lt;span class="err"&gt;@$(OBJCOPY)&lt;/span&gt; &lt;span class="err"&gt;-O&lt;/span&gt; &lt;span class="err"&gt;binary&lt;/span&gt; &lt;span class="err"&gt;$(FIRMWARE_ELF)&lt;/span&gt; &lt;span class="err"&gt;$(FIRMWARE_BIN)&lt;/span&gt;
    &lt;span class="err"&gt;@$(RM)&lt;/span&gt; &lt;span class="err"&gt;$(OBJECTS)&lt;/span&gt;

    &lt;span class="err"&gt;@echo&lt;/span&gt; &lt;span class="s2"&gt;"\n-------------------------------------"&lt;/span&gt;
    &lt;span class="err"&gt;@echo&lt;/span&gt; &lt;span class="s2"&gt;"----- The firmware memory usage -----"&lt;/span&gt;
    &lt;span class="err"&gt;@echo&lt;/span&gt; &lt;span class="s2"&gt;"-------------------------------------"&lt;/span&gt;
    &lt;span class="err"&gt;@$(SIZE)&lt;/span&gt; &lt;span class="err"&gt;$(FIRMWARE_ELF)&lt;/span&gt;

    &lt;span class="err"&gt;@echo&lt;/span&gt; &lt;span class="s2"&gt;"\n-------------------------------------"&lt;/span&gt;
    &lt;span class="err"&gt;@echo&lt;/span&gt; &lt;span class="s2"&gt;"----- The firmware binary format ----"&lt;/span&gt;
    &lt;span class="err"&gt;@echo&lt;/span&gt; &lt;span class="s2"&gt;"-------------------------------------"&lt;/span&gt;
    &lt;span class="err"&gt;@$(FILE)&lt;/span&gt; &lt;span class="err"&gt;$(FIRMWARE_ELF)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly, run the Makefile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;make
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it 🥳🥳🥳. You've built the both &lt;strong&gt;firmware.elf&lt;/strong&gt; and &lt;strong&gt;firmware.bin&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You are ready to flash the built firmware into microcontroller with this or similar command (over ST-Link connection):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;openocd &lt;span class="nt"&gt;-f&lt;/span&gt; interface/stlink.cfg &lt;span class="nt"&gt;-f&lt;/span&gt; target/stm32f4x.cfg &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"program firmware.elf verify reset exit"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>c</category>
      <category>programming</category>
      <category>computerscience</category>
      <category>lowcode</category>
    </item>
  </channel>
</rss>
