Home / Alt manpages / x86_64-w64-mingw32-as(1)

  • x86_64-w64-mingw32-as(1)
  • User command
  • linux

Assemble x86-64 MinGW Code and Inspect the Object Safely

x86_64-w64-mingw32-as turns one small assembly file into an x86-64 Windows object, and this guide checks its sections and symbols once it exists. The examples use the installed x86_64-w64-mingw32-as from the binutils-mingw-w64-x86-64 package. Expect about 10 minutes if the toolchain is already installed. No elevated privileges needed.

Before you start

Have a shell, the MinGW assembler, and an object inspection tool ready. Check the exact binary and target before trusting any example:

command -v x86_64-w64-mingw32-as
x86_64-w64-mingw32-as --version
x86_64-w64-mingw32-as --dump-config

On the machine used for this guide, the assembler reports GNU Binutils 2.41.90.20240122 and the target x86_64-w64-mingw32. The paired x86_64-w64-mingw32ucrt-as manpage describes the same assembler build and target family. Treat those details as local facts, another package revision may accept a different set of target extensions.

Checkpoint

Continue only once the version output names the assembler you actually intend to use. Missing command? Install the distribution package through your normal package-management process, that is an administrative change, outside the assembly steps here.

1. Create a minimal source file

Save this as add-one.s. It follows the GNU assembler syntax shown by the installed target. The x86-64 Windows calling convention passes the first integer argument in %ecx, and the function returns it in %eax.

.text
.globl add_one
.def add_one; .scl 2; .type 32; .endef
add_one:
    movl %ecx, %eax
    addl $1, %eax
    ret

.text selects the code section and .globl makes the entry point visible to the linker. The .def line supplies COFF symbol metadata for this MinGW object. This is an object-file input, not a complete executable, so assembling it does not run the function or touch a system anywhere.

Check the source for accidental typographical substitutions before assembling. A straight ASCII hyphen in an option and a percent sign in a register name matter, and copying formatted text from a document can silently swap either one.

2. Assemble deliberately as 64-bit

Run the assembler with an explicit output path:

x86_64-w64-mingw32-as --64 -o add_one.o add-one.s

The target is already x86-64, but --64 records the intended word size in the command itself. The manpage defines --32, --x32, and --64 for the i386 backend, describing ELF word-size modes in the generic documentation. This MinGW invocation produces a PE/COFF object instead, so verify the actual file rather than inferring its format from the switch.

A successful assembly normally prints nothing and returns status zero:

test -f add_one.o && echo "object created"
file add_one.o

Expect object created and wording similar to Intel amd64 COFF object file, with the format identified as pe-x86-64. That exact wording belongs to file, not to as, so do not treat it as a stable interface to parse.

Checkpoint

You now have an object file, not a Windows executable. Linking it needs a suitable linker and runtime or entry point. Do not try to execute add_one.o directly.

3. Inspect sections and symbols

Use the target-prefixed inspection tools when they are installed:

x86_64-w64-mingw32-objdump -h add_one.o
x86_64-w64-mingw32-nm add_one.o

The section listing should contain a .text section marked as code, and the symbol listing should contain add_one. That confirms the source assembled into the right kind of object, and that the entry point was not left local by mistake.

For a byte-level view, disassemble the object:

x86_64-w64-mingw32-objdump -dr add_one.o

You should see the move from %ecx to %eax, the increment, and the return instruction. Relocations show up if the source refers to symbols whose final addresses are not yet known at assembly time.

4. Add a listing when the source is hard to read

The -a family enables listings. For an assembly listing with source lines, write it to a separate file:

x86_64-w64-mingw32-as --64 -al=add_one.lst -o add_one.o add-one.s
sed -n '1,30p' add_one.lst

The listing combines source lines with addresses and emitted bytes. Keep it as a debugging aid, not a replacement for inspecting the object itself. Pass -a without a sub-option and the assembler defaults to a broader listing; -al is more focused for this example.

5. Make architecture choices explicit

Use -march when the source deliberately depends on an instruction set. The installed manpage lists generic64, znver4, and many extension names, for example. This command asks the assembler to accept AVX2 instructions:

x86_64-w64-mingw32-as --64 -march=generic64+avx2 -o vector.o vector.s

Only choose an extension supported by every CPU that will run the resulting program. Assembly success proves the selected assembler accepts the instruction, it does not prove an older deployment machine can execute it. If -march rejects an instruction, either change the source or pick a target that matches the real deployment boundary.

Source uses / in an expression? Remember the target-specific --divide option. The installed documentation says it makes slash an ordinary expression character on systems where slash otherwise starts a comment, while leaving a slash at the start of a comment line unaffected. Do not add it out of habit, use it only when the source actually needs that interpretation.

6. Diagnose failures without hiding them

For a quick option summary, use:

x86_64-w64-mingw32-as --help
x86_64-w64-mingw32-as --target-help
  • Missing input file. Usually a path or working-directory error. Pass the source path explicitly and check it with test -r add-one.s.
  • Unknown instruction. Often the -march choice is too old, or an extension was omitted. Check the target option summary before changing syntax.
  • A warning appears. That can mean the assembler made an assumption to let assembly continue. Add --fatal-warnings in CI when warnings must fail the build.
  • --defsym NAME=VALUE defines an integer symbol before assembly. Values starting 0x are hexadecimal and values starting 0 are octal. Keep build-time inputs like this visible in logs.

Warning

Do not use -Z as a recovery technique. The manpage says it can generate an object after errors, useful for specialised diagnostics but dangerous if that object slips into a normal build. If assembly fails, remove or quarantine the output before retrying. The example above only creates local files, so recovery is simply deleting add_one.o and add_one.lst and rerunning the corrected command.

Done means

  • Identified the toolchain. x86_64-w64-mingw32-as --version named the intended assembler.
  • Assembled cleanly. The source assembled with status zero and produced add_one.o.
  • Confirmed the format. file reported an x86-64 PE/COFF object.
  • Checked the contents. objdump showed a code section and nm showed add_one.
  • Matched the deployment target. Instruction extensions were chosen for the CPUs that will run the program, not just for what the assembler accepts.