30

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.

1
  • 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. Commented Sep 15, 2015 at 20:08

2 Answers 2

23

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

Sign up to request clarification or add additional context in comments.

6 Comments

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.
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.
When I disassemble the NASM code, it shows: callq 0xfffffffffff00040 for call xyz where xyz equ 0x0000000000100040.
Thanks again by the way! The goal here is to generate binaries for BareMetal 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.
Also, when I disassemble the (not working) GAS code, it shows callq *0x100040 for call xyz where .set xyz , 0x0000000000100040.
|
12

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:

2 Comments

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?
@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.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.