Skip to content

yousabmenissy/cur

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

cur

An opinionated autoformatter for the GNU assembler, as.

cur is the result of my long-brewing frustration with the complete lack of open source GAS autoformatters.

Table of Contents

Installation

Unix/Linux

git clone https://github.com/yousabmenissy/cur.git
cd cur
sudo make install

Windows

If gcc is not installed, install it first via MinGW or TDM-GCC. you can check with:

gcc --version

Press Win + S and type cmd, Right-click Command Prompt and select Run as administrator.

run these commands:

git clone https://github.com/yousabmenissy/cur.git
cd cur
gcc main.c lib/*.c -o cur.exe -Ilib -O3
if not exist "C:\Program Files\cur" mkdir "C:\Program Files\cur"
move cur.exe "C:\Program Files\cur"
powershell -Command "[System.Environment]::SetEnvironmentVariable('Path', $env:Path + ';C:\Program Files\cur', 'Machine')"

Usage

Provide cur with 1 or more file names to format:

cur atoi.s putd.s

By default cur will use standard output. To format files in place use the -w flag:

cur atoi.s putd.s -w

You can use the -v flag to make cur print the processed files names:

cur *.s -w -v

Benchmark

The makefile include a perf section that will use the perf stat command to print performance stats:

make perf

For testing data, an unformatted disassembled file is generated from he source code of cur itself:

gcc main.c lib/*.c -S -fno-asynchronous-unwind-tables -Ilib && cat *.s > seed.s

seed.s will contain approximately 2000 lines of assembly generated by the gcc compiler.

here's an example of the output make perf will produce:

gcc main.c lib/*.c -o cur -Ilib -O3
gcc main.c lib/*.c -S -fno-asynchronous-unwind-tables -Ilib
cat *.s > seed.s
sudo perf stat ./cur seed.s -w

 Performance counter stats for './cur seed.s -w':

              1.10 msec task-clock                       #    0.495 CPUs utilized          
                28      context-switches                 #   25.474 K/sec                  
                 0      cpu-migrations                   #    0.000 /sec                   
                67      page-faults                      #   60.955 K/sec                  
         3,376,957      cycles                           #    3.072 GHz                    
         2,023,753      stalled-cycles-frontend          #   59.93% frontend cycles idle   
         1,568,398      stalled-cycles-backend           #   46.44% backend cycles idle    
         2,730,462      instructions                     #    0.81  insn per cycle         
                                                  #    0.74  stalled cycles per insn
           643,580      branches                         #  585.513 M/sec                  
            21,647      branch-misses                    #    3.36% of all branches        

       0.002218476 seconds time elapsed

       0.001623000 seconds user
       0.000000000 seconds sys


rm *.s -f cur

Formatting rules

Blank characters

The characters '\n', '\t' and '\s' are treated as blanks.

  • tabs and spaces at the start of the line are ignored.
  • tabs and spaces before the end of the line are ignored.
  • multible lines of blank characters are all replaced with a single '\n' character.
  • cur will make sure the last character in the file is a new line, '\n'.

Directives

Expressions that start with '.', does not end with ':' are treated as directives.

  • they are always at indentaion level 0.
  • their operands are aligned by 1 space.

Global labels

Expressions that does not start with '.', does not compose of a signle digit, and end with ':' are treated as global labels.

  • they are always at indentaion level 0.
  • cur will allow either a space, tab or a new line to follow the ':'.
  • if ':' is not followed by either a space, tab or a new line, cur will inject a new line after the colon and treats the rest as a different line

Local labels

Expressions that start with '.', or compose of a signle digit, and end with ':' are treated as local labels.

  • they are always at indentaion level 1.
  • cur will allow either a space, tab or a new line to follow the ':'.
  • if ':' is not followed by either a space, tab or a new line, cur will inject a new line after the colon and treats the rest as a different line
  • a new line will be inserted before it if the previous expression was an instruction.

Signle line comments

lines that start with '#' or '//' are treated as single line comments.

  • they follow the indentaion of the previous line
  • if '//' is used, cur will replace it with '#' followed by a space.
  • blank lines at the start of the comment are ignored.
  • comments that come after other expressions in the line are not formated

Multi line comments

lines that start with /* are treated as multi-line comment untill */ or end of the file is reached.

  • blank lines at the start and end of the comment are ignored, other blanks are uneffected.
  • everything inside the comment is always at indentation level 1.
  • the /* and */ are set on their own lines with no indentaion.

Instructions

lines that is not recognized as directives, labels, or comments are treated as instructions.

  • they are always at indentaion level 1.
  • their operands are aligned with 2 spaces after the longest instruction in the block.
  • each block has it's own alignment.
  • a block start at the first instruction and end at the next blank line.
  • instruction without operands are not cosidered when finding the alignment.
  • a space is injected after each ',' in the operands list.
  • macro calls are treated exactly like instructions.

Example

Before

 .section .text


        .global basename
 .type basename, @function

  //       basename(path)
    basename: 
movq %rdi, %rsi
xor %rax,    %rax

 .LPBN0:lodsb
    cmpb $'/',%al
    cmove    %rsi,%rdi


    cmpq $0,        %rax
    jne .LPBN0
    movq      %rdi,%rax

ret
/*## Altered Registers ##
- rdi
 - rsi*/

After

.section .text

.global basename
.type basename, @function

# basename(path)
basename:
    movq  %rdi, %rsi
    xor   %rax, %rax

    .LPBN0:
    lodsb
    cmpb   $'/', %al
    cmove  %rsi, %rdi

    cmpq  $0, %rax
    jne   .LPBN0
    movq  %rdi, %rax

    ret
/*
    ## Altered Registers ##
    - rdi
    - rsi
*/

Before

.section .text


.global itoa
.type itoa, @function


itoa: # itoa(int, buff)
movq %rdi, %rax

 testq    %rax,   %rax
  jns      1f
imul   $-1,    %rax

1:
    xor   %rcx, %rcx
    xor      %rdx,    %rdx
    movq    $10, %r8

 .LPITOA0:
    incq    %rcx
    xor    %rdx, %rdx
    div     %r8
    addq $'0', %rdx
    movb %dl, -1(%rsi, %rcx)
    cmpq $0, %rax
    jne  .LPITOA0

    testq %rdi, %rdi
    jns   1f
    incq        %rcx
    movb        $'-',    -1(%rsi, %rcx)

  1:
    movb $0,   (%rsi, %rcx) # Null terminate the string

 //     Reverse the string
    movq %rsi,  %rax
    addq %rcx,  %rax
    decq %rax
     movq %rax,  %rdi

.LPITOA1:
    cmpq %rsi,   %rdi
    jb   1f
    movb (%rsi),   %al
    movb (%rdi),   %dl
    movb %al,      (%rdi)
    movb %dl,     (%rsi)
    incq %rsi
    decq %rdi
    jmp .LPITOA1

    1:
    movq  %rcx, %rax
    ret

After

.section .text

.global itoa
.type itoa, @function

itoa: # itoa(int, buff)
    movq  %rdi, %rax

    testq  %rax, %rax
    jns    1f
    imul   $-1, %rax

    1:
    xor   %rcx, %rcx
    xor   %rdx, %rdx
    movq  $10, %r8

    .LPITOA0:
    incq  %rcx
    xor   %rdx, %rdx
    div   %r8
    addq  $'0', %rdx
    movb  %dl, -1(%rsi, %rcx)
    cmpq  $0, %rax
    jne   .LPITOA0

    testq  %rdi, %rdi
    jns    1f
    incq   %rcx
    movb   $'-', -1(%rsi, %rcx)

    1:
    movb  $0, (%rsi, %rcx) # Null terminate the string

    # Reverse the string
    movq  %rsi, %rax
    addq  %rcx, %rax
    decq  %rax
    movq  %rax, %rdi

    .LPITOA1:
    cmpq  %rsi, %rdi
    jb    1f
    movb  (%rsi), %al
    movb  (%rdi), %dl
    movb  %al, (%rdi)
    movb  %dl, (%rsi)
    incq  %rsi
    decq  %rdi
    jmp   .LPITOA1

    1:
    movq  %rcx, %rax
    ret
    

Projects using cur

You can see more formatting examples at aslib and aslib-examples. Containing a combined total of over 8000 lines of assembly formatted with cur.

License

Copyright (c) 2025-present Yousab Menissy

Licensed under MIT License. See the LICENSE file for details.

About

An opinionated autoformatter for the GNU assembler

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published