26

I have some NASM files that generally have the structure:

        [BITS 64]
        [ORG 0x0000000000200000]

start:
        ...

        ret

I'm assembling them like so:

nasm -f bin abc.asm

I'd like to write some of these using GAS instead. Two questions:

  • What directives should I use in GAS? I've found the '.org' directive but GAS doesn't seem to have a '.bits' directive.

  • What should I pass to gcc or as to generate a plain binary file? I.e. what the -f bin option does with NASM.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
dharmatech
  • 8,979
  • 8
  • 42
  • 88
  • Out of curiosity: what is the target platform for that code? The most common I've seen is to see 16-bit bare assembly for boot sectors, but this is not the case since you're in 64-bits. – Ciro Santilli OurBigBook.com Sep 15 '15 at 20:08

2 Answers2

22

What directives should I use in GAS? I've found the '.org' directive but GAS doesn't seem to have a '.bits' directive.

The assembler defaults to 64--bit for me, you can use --32 or --64 to chose on the command line. Have a look at the manual for as to see how you can change the architecture inside the code if needed (e.g. .code16 can be used to generate real mode code for a boot loader).

You most likely don't want to use the .org directive to specify where the code is located, but will probably want to use a link script or specify where the text and data segments are loaded on the command line. (org 0x0000000000200000 results in a 2+ MB binary file).

What should I pass to gcc or as to generate a plain binary file? I.e. what the -f bin option does with NASM.

$ cat test.S
.section .text
.globl _start
_start:
        xor %rax, %rax
        mov test, %rax
        ret

test: .quad 0x1234567812345678


$ as --64 -o test.o test.S
$ ld -Ttext 200000 --oformat binary -o test.bin test.o

$ objdump -D -b binary -m i386:x86-64 test.bin
test.bin:     file format binary
Disassembly of section .data:

0000000000000000 <.data>: 0: 48 31 c0 xor %rax,%rax 3: 48 8b 04 25 0c 00 20 mov 0x20000c,%rax a: 00 b: c3 retq
c: 78 56 js 0x64 e: 34 12 xor $0x12,%al 10: 78 56 js 0x68 12: 34 12 xor $0x12,%al

user786653
  • 29,780
  • 4
  • 43
  • 53
  • The original NASM files include a file which contains lines like: `xyz equ 0x0000000000100010`. They then are able to do `call xyz`. I tried to do the same in GAS but this doesn't seem to work. I.e. using `.set xyz , 0x0000000000100010` and later `call xyz` doesn't seem to do the trick. Any thoughts? Perhaps I should open a separate question. – dharmatech Jul 26 '11 at 12:25
  • What kind of jump do you want? I don't think an absolute 64-bit call is possible. For indirect call you need `call *xyz`. – user786653 Jul 26 '11 at 12:34
  • When I disassemble the NASM code, it shows: `callq 0xfffffffffff00040` for `call xyz` where `xyz equ 0x0000000000100040`. – dharmatech Jul 26 '11 at 12:39
  • Thanks again by the way! The goal here is to generate binaries for [BareMetal](http://www.returninfinity.com/baremetal.html) OS using GAS. Very simple ones which don't reference system calls are now working. Now I'm trying to resolve the above equ/call issue to access the system calls. – dharmatech Jul 26 '11 at 12:43
  • Also, when I disassemble the (not working) GAS code, it shows `callq *0x100040` for `call xyz` where `.set xyz , 0x0000000000100040`. – dharmatech Jul 26 '11 at 12:47
  • Try `.set xyz, $0x0000000000100040`, otherwise open a new question. – user786653 Jul 26 '11 at 12:55
11

objcopy -O binary

A good option is:

as -o test.o test.S
ld -Ttext 0x7C00 -o test.elf test.o
objcopy -O binary kernel.elf kernel.bin

The advantage over ld --oformat binary is that it is easier to use the symbols to debug via:

qemu-system-i386 -hda main.img -S -s &
gdb main.elf -ex 'target remote localhost:1234'

See also: https://stackoverflow.com/a/32960272/895245

Linker script

-Ttext is fine for quick and dirty testing, but for serious work you should use a script instead to increase robustness.

Otherwise, ld will use a default script (ld --verbose) intended for userland application, which does not look like your application.

Without further information, the minimal script I can give is:

SECTIONS
{
    . = 2M;
    .text :
    {
        *(.*)
    }
}

And then use it with -T:

as --64 -o test.o test.S
ld -T linker.ld --oformat binary -o test.bin test.o

But you will likely want to modify that script based on your exact application.

See also: Is there a way to get gcc to output raw binary?

I have a repository with working examples for some common use cases:

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
  • 2
    why do some people religiously do gcc -o outfile infile or as -o outfile infile when the att convention uses first as input, second as output . I know flex/bison dont even work if you put input before output. Whats the reasoning behind this? – Dmytro May 09 '18 at 16:37
  • 4
    @Dmitry to follow the same convention as most other CLI tools: first optional arguments `-o val` and then positional ones. Especially relevant when using `-- -positional -with -leading hyphens`. – Ciro Santilli OurBigBook.com May 09 '18 at 16:43