26

gcc can produce assembly but how do I compile pure assembly with gcc or other compiler? I know x86 assembly is difficult and another instruction set than the MIPS and Nios I was looking at but now I want to try to compile direct x86 asm. There are instruction for how to do it but there's a C file included and I don't need a C file for my first most basic compile.

gcc -o test_asm asm_functions.S test_asm.c

There's the step creating .o files

gcc -c asm_functions.S
gcc -c test_asm.c
gcc -o test_asm asm_functions.o test_asm.o

But I don't see the step where I can directly compile x86 asm with gcc. There's another program named GNU as (GNU Assembler), can it be used to translate x86 assembly to machine code?

Test

Code (32.s)

.globl  _start

.text
_start:
        movl    $len, %edx
        movl    $msg, %ecx
        movl    $1, %ebx
        movl    $4, %eax
        int     $0x80

        movl    $0, %ebx
        movl    $1, %eax
        int     $0x80
.data
msg:
        .ascii  "Hello, world!\n"
        len =   . - msg

Steps

$ gcc -c 32.s 
$ ls 32*
32.o  32.s
$ gcc -o 32 32.o 
32.o: In function `_start':
(.text+0x0): multiple definition of `_start'
/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/crt1.o:(.text+0x0): first defined here
/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/crt1.o: In function `_start':
(.text+0x20): undefined reference to `main'

So it seems it may have mixed 32 and 64 bits, must I tell the complier whether the assembly is 32 or 64 bit instructions?

Update

This test worked with gcc.

$ cat hello.s
.data
.globl hello
hello:
.string "Hi World\n"

.text
.global main
main:
    pushq   %rbp
    movq    %rsp,       %rbp
    movq    $hello,     %rdi
    call    puts
    movq    $0,         %rax
    leave
    ret
$ gcc hello.s -o hello
$ ./hello 
Hi World
Niklas Rosencrantz
  • 25,640
  • 75
  • 229
  • 424
  • 2
    Yes, that's exactly what `as(1)` does. – cnicutar Feb 18 '13 at 06:45
  • 1
    See also [this Q&A](http://stackoverflow.com/questions/36861903/assembling-32-bit-binaries-on-a-64-bit-system-gnu-toolchain/36901649#36901649) on how to assemble and link using gcc, for programs that define `_start` or `main`, with/without libc. – Peter Cordes Jul 07 '16 at 23:08

2 Answers2

20

You're already doing it.

gcc -c asm_functions.S

That step produces an object file, asm_functions.o. The object file is "linkable" (as opposed to "loadable") file that contains the machine code, with some extra instructions for how the linker should modify the code when linking. The gcc program itself is just a driver, it runs as behind the scenes for you to produce asm_functions.o. So you do have the option of running as directly, but often it's easier to run the gcc frontend.

Dietrich Epp
  • 205,541
  • 37
  • 345
  • 415
  • But when I try to link just an object file created from pure assembly I get an error message I can't understand (`In function `_start': (.text+0x0): multiple definition of `_start' /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/crt1.o:(.text+0x0): first defined here /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/crt1.o: In function `_start': (.text+0x20): undefined reference to `main'` Thank you for the answer. – Niklas Rosencrantz Feb 18 '13 at 07:29
  • 5
    That's a linking problem, not a compiling problem! If you use `gcc` to link, you get the C runtime by default, and your entry point should be `main`. – Dietrich Epp Feb 18 '13 at 07:32
  • 3
    Thanks. It works (`gcc hello.s -o hello`) to compile and run to x86 assembly now. I updated the question with the code and cmd I use. I didn't try whether this code is spec to linux, it may be other assembly for other operating systems and the `as` program might also compile it but in this case I could use `gcc` with a simple hello world program to compile and run x86 assembly. – Niklas Rosencrantz Feb 19 '13 at 01:04
3

Although the update works, the original code could have been compiled by simply using gcc -nostdlib. For example,

gcc -nostdlib 32.s -o 32
Community
  • 1
  • 1
Darryl W
  • 31
  • 1
  • 1
    Unlikely that passing your name as a parameter would have much effect. And what's that random 32? Using line breaks and code formatting would make your answer much more readable. – Cody Gray - on strike Jul 07 '16 at 18:29
  • 1
    Some code will also benefit from (or require) `-no-pie` on modern distros. no-pie used to be the default, but isn't anymore in most modern GNU/Linux distro GCC configs. Especially for 64-bit code using absolute addresses. With `gcc -m32 -nostdlib foo.S`, it may still work to build a PIE, but if you do link libc then you need puts@plt or manual -fno-plt asm;see [Can't call C standard library function on 64-bit Linux from assembly (yasm) code](https://stackoverflow.com/a/52131094) – Peter Cordes Sep 08 '21 at 12:41