Skip to main content
Redhat Developers  Logo
  • Products

    Featured

    • Red Hat Enterprise Linux
      Red Hat Enterprise Linux Icon
    • Red Hat OpenShift AI
      Red Hat OpenShift AI
    • Red Hat Enterprise Linux AI
      Linux icon inside of a brain
    • Image mode for Red Hat Enterprise Linux
      RHEL image mode
    • Red Hat OpenShift
      Openshift icon
    • Red Hat Ansible Automation Platform
      Ansible icon
    • Red Hat Developer Hub
      Developer Hub
    • View All Red Hat Products
    • Linux

      • Red Hat Enterprise Linux
      • Image mode for Red Hat Enterprise Linux
      • Red Hat Universal Base Images (UBI)
    • Java runtimes & frameworks

      • JBoss Enterprise Application Platform
      • Red Hat build of OpenJDK
    • Kubernetes

      • Red Hat OpenShift
      • Microsoft Azure Red Hat OpenShift
      • Red Hat OpenShift Virtualization
      • Red Hat OpenShift Lightspeed
    • Integration & App Connectivity

      • Red Hat Build of Apache Camel
      • Red Hat Service Interconnect
      • Red Hat Connectivity Link
    • AI/ML

      • Red Hat OpenShift AI
      • Red Hat Enterprise Linux AI
    • Automation

      • Red Hat Ansible Automation Platform
      • Red Hat Ansible Lightspeed
    • Developer tools

      • Red Hat Trusted Software Supply Chain
      • Podman Desktop
      • Red Hat OpenShift Dev Spaces
    • Developer Sandbox

      Developer Sandbox
      Try Red Hat products and technologies without setup or configuration fees for 30 days with this shared Openshift and Kubernetes cluster.
    • Try at no cost
  • Technologies

    Featured

    • AI/ML
      AI/ML Icon
    • Linux
      Linux Icon
    • Kubernetes
      Cloud icon
    • Automation
      Automation Icon showing arrows moving in a circle around a gear
    • View All Technologies
    • Programming Languages & Frameworks

      • Java
      • Python
      • JavaScript
    • System Design & Architecture

      • Red Hat architecture and design patterns
      • Microservices
      • Event-Driven Architecture
      • Databases
    • Developer Productivity

      • Developer productivity
      • Developer Tools
      • GitOps
    • Secure Development & Architectures

      • Security
      • Secure coding
    • Platform Engineering

      • DevOps
      • DevSecOps
      • Ansible automation for applications and services
    • Automated Data Processing

      • AI/ML
      • Data Science
      • Apache Kafka on Kubernetes
      • View All Technologies
    • Start exploring in the Developer Sandbox for free

      sandbox graphic
      Try Red Hat's products and technologies without setup or configuration.
    • Try at no cost
  • Learn

    Featured

    • Kubernetes & Cloud Native
      Openshift icon
    • Linux
      Rhel icon
    • Automation
      Ansible cloud icon
    • Java
      Java icon
    • AI/ML
      AI/ML Icon
    • View All Learning Resources

    E-Books

    • GitOps Cookbook
    • Podman in Action
    • Kubernetes Operators
    • The Path to GitOps
    • View All E-books

    Cheat Sheets

    • Linux Commands
    • Bash Commands
    • Git
    • systemd Commands
    • View All Cheat Sheets

    Documentation

    • API Catalog
    • Product Documentation
    • Legacy Documentation
    • Red Hat Learning

      Learning image
      Boost your technical skills to expert-level with the help of interactive lessons offered by various Red Hat Learning programs.
    • Explore Red Hat Learning
  • Developer Sandbox

    Developer Sandbox

    • Access Red Hat’s products and technologies without setup or configuration, and start developing quicker than ever before with our new, no-cost sandbox environments.
    • Explore Developer Sandbox

    Featured Developer Sandbox activities

    • Get started with your Developer Sandbox
    • OpenShift virtualization and application modernization using the Developer Sandbox
    • Explore all Developer Sandbox activities

    Ready to start developing apps?

    • Try at no cost
  • Blog
  • Events
  • Videos

Tips for writing portable assembler with GNU Assembler (GAS)

February 26, 2021
Nick Clifton
Related topics:
LinuxOpen source
Related products:
Developer Tools

Share:

    Writing assembly code is straightforward when you are familiar with the targeted architecture's instruction set, but what if you need to write the code for more than one architecture? For example, you might want to test whether a particular assembler feature is available, or generate an object file for use with another tool. Writing assembly source code that can work on multiple architectures is not so simple.

    This article describes common types of problems encountered when working with assembly code, and the techniques to overcome them. You will learn how to address problems with comments, data, symbols, instructions, and sections in assembly code. To get you started, the Portable assembler demo source file provides many examples of GNU Assembler (GAS) assembly code. I'll use a few of the examples in this article.

    Problems with comments

    There is no architecture-neutral way of creating a prefixed line comment. As a result,

      # This is a comment
    

    might or might not work, depending on the target. (On some architectures the hash character is actually part of the instruction set, similarly for the semicolon and colon characters.)

    Instead, the safe approach is to use C-like comments:

      /* This is a comment. */
    

    But keep in mind that these comments cannot be nested:

      /* This is /* not a */ valid comment. */
    

    Problems with data

    The size of individual data items, such as integers, pointers, floats, and so on, varies from one architecture to another. Take the following example:

      .data
      .word 0x12345678
    

    This code would fail to assemble on machines where a word was less than 4 bytes long. (Fortunately, the .data directive is universal.)

    A more reliable way to insert specific integer values is to use the .dc.<letter> directives, where <letter> is b for bytes, w for 16-bit values, and l for 32-bit values. Here's an example:

      .data
      .dc.b 0x78
      .dc.w 0x5678
      .dc.l 0x12345678
    

    This assembly code works on all targets, regardless of their word size.

    Inserting 64-bit integer values

    Oddly, the directive for 64-bit values does not follow the same naming scheme. Instead the directive to use is .quad:

      .quad 0x1234567890abcdef

    Endian-ness

    All values are stored in the target's endian format, which is usually the right approach. However, when fixed ordering is required, specifying multiple single-byte values is the way to go:

      .data
      .dc.b 0x78, 0x56, 0x34, 0x12
    

    This code produces a little-endian ordering of bytes, even on a big-endian architecture. You cannot however create multi-byte bit patterns on targets where the byte size is larger than 8 bits (for example, the Texas Instrument's TIC54x.) Outside assistance is the only way to handle this particular situation:

      .data
      .ifdef big_bytes
      .dc.b 0x5678, 0x1234
      .else
      .dc.b 0x78, 0x56, 0x34, 0x12
      .endif
    

    This solution works provided the symbol, big_bytes, is defined for architectures with 16-bit bytes and not otherwise. (Symbols can be defined on the GAS command line with --defsym <name>=<value>.)

    Alignment requirements

    Another problem with directives that store data values is that they can have alignment requirements. For example:

      .data
      .dc.b 0xff
      .dc.l 0x12345678
    

    This example fails to assemble for the SH target because the 4 bytes in 0x12345678 are not being stored on a 4-byte aligned boundary. You can solve this issue with an alignment directive, but be cautious of using .align, which has target-specific semantics. Instead, use either the .balign or .p2align directives:

    .data
      .dc.b 0xff
      .balign 4
      .dc.l 0x12345678
    

    Note that this code introduces a gap between the 0xff byte and the 0x12345678 word.

    Fixed values

    GAS supports simple arithmetic and logical operations on symbols and constants. For most directives, the result must be a fixed value. Here's an example:

      .dc.b (val & 0xff), (val >> 8) & 0xff
    

    This code works provided that the symbol val has a defined value when the directive is evaluated.

    Storing strings

    Strings can be stored easily, but beware that the .ascii directive does not store a terminating NUL byte. For C like strings use the .asciz directive instead:

      .ascii "this string has no NUL byte at the end"
      .asciz "this string does"
    

    Problems with symbols

    Labels and symbols are defined in various ways, all of which work across most targets:

      val = 0x1234
      .equiv here, .
      .equiv there, here + 4
      this_is_a_label:
    

    For comparability with the HPPA assembler however, it is necessary to start a label's name in the first column of a line. Plus, by extension, the first column on any line needs to contain a whitespace character if no label is being defined.

    If a symbol or label holds an address, then it is safest to insert it into the code using the .dc.a directive, like so:

      .dc.a this_is_a_label
    

    You can perform simple addition or subtraction operations on an address, but more complicated operations are often not supported. Calculating the difference between two labels usually works only when they are defined in the same section, and sometimes not even then:

      .dc.a label1 - 2      /* This will work. */
      .dc.a label1 - label2 /* This might not work. */
    

    Problems with instructions

    Typically, instructions are specific to individual architectures. As a result, you cannot write a generic assembler source file that involves code. Starting with GAS 2.35 however, there is a new pseudo-op instruction (.nop), which generates a no-op instruction on any target:

      .text
      .nop /* This is a real instruction. */
    

    Problems with sections

    All architectures accept the section names .text, .data, and .bss. The old AOUT file format only supports these names. More modern formats such as Portable Executable (PE) and Executable and Linkable Format (ELF) support arbitrary section names. When defining new sections, be aware that the .section directive for ELF targets accepts more arguments than does the PE version:

      .section name                  /* See note 1. */
      .section name, "flags"         /* See note 2. */
      .section name, "flags", %type  /* See note 3. */
    

    Notes:

    1. This form fails on targets where the section flags are compulsory.
    2. This form works for both PE-based and ELF-based targets, although the flags are different.
    3. This form only works on ELF-based targets. Note the use of the % character instead of the @ character.

    Conclusion

    This article addressed common problems writing portable assembly code and provided solutions and examples. In summary, writing portable assembler is hard to do and best kept simple, and persistence is the key.

    Last updated: February 5, 2024

    Recent Posts

    • Build container images in CI/CD with Tekton and Buildpacks

    • How to deploy OpenShift AI & Service Mesh 3 on one cluster

    • JVM tuning for Red Hat Data Grid on Red Hat OpenShift 4

    • Exploring Llama Stack with Python: Tool calling and agents

    • Enhance data security in OpenShift Data Foundation

    Red Hat Developers logo LinkedIn YouTube Twitter Facebook

    Products

    • Red Hat Enterprise Linux
    • Red Hat OpenShift
    • Red Hat Ansible Automation Platform

    Build

    • Developer Sandbox
    • Developer Tools
    • Interactive Tutorials
    • API Catalog

    Quicklinks

    • Learning Resources
    • E-books
    • Cheat Sheets
    • Blog
    • Events
    • Newsletter

    Communicate

    • About us
    • Contact sales
    • Find a partner
    • Report a website issue
    • Site Status Dashboard
    • Report a security problem

    RED HAT DEVELOPER

    Build here. Go anywhere.

    We serve the builders. The problem solvers who create careers with code.

    Join us if you’re a developer, software engineer, web designer, front-end designer, UX designer, computer scientist, architect, tester, product manager, project manager or team lead.

    Sign me up

    Red Hat legal and privacy links

    • About Red Hat
    • Jobs
    • Events
    • Locations
    • Contact Red Hat
    • Red Hat Blog
    • Inclusion at Red Hat
    • Cool Stuff Store
    • Red Hat Summit
    © 2025 Red Hat

    Red Hat legal and privacy links

    • Privacy statement
    • Terms of use
    • All policies and guidelines
    • Digital accessibility

    Report a website issue