2

I want to study the detail of an obj file, I have produced an main.S file, when I use as main.S I get an a.out file in return which can be run directly with ./a.out and ld -m elf_x86_64 a.out would produce an error.

I want to produce an object file of which the file type is the same with the result of clang -c main.c. How can I do that?


I may have mix up the operation, which resulting a wrong interpretation. as does not produce an executable, the executable is result of clang. thank you to all answerers, I am very sorry to cause confusion, and have wasted your time.

Rui
  • 89
  • 1
  • 8
  • 1
    What have you done to assemble the object file? You can do `cc -c main.S` to get such an object file. Or use `clang` or any other compiler instead of `cc`. – fuz Mar 22 '21 at 09:32
  • I am trying to manipulate the middle result to see what would came out as a final result to learn reverse engineering. – Rui Mar 22 '21 at 13:39
  • @Riu Your question is correctly phrased "I want to produce an object file of which the file type is the same with the result of clang -c main.c". And you tried to link the resultant object file with `ld`, so it doesn't seem that you have misunderstood preproc/asm/COFF/linking stages in the executable build process ^^ – Zilog80 Mar 22 '21 at 14:09
  • @Riu I suggest you to rephrase your question title with something more accurate with your intent like "How can i produce an object file from an assembler source in the same way as clang -c main.c does" – Zilog80 Mar 22 '21 at 14:26
  • 1
    Thank you @zilog80, I have changed that. – Rui Mar 22 '21 at 14:31

2 Answers2

3

as -o foo.o foo.s

If you have a .S, normally that means you want to run it through the C preprocessor before assembling. The gcc and clang front-ends will do that for you: gcc -c foo.S (default output filename foo.o, instead of a.out). If your .S doesn't actually have any CPP directives like #if or #define, though, you can just assemble it with as.


a.out is the default name for the output of as, but it is an object file like you'd get from gcc -c foo.s, not a linked executable! GNU Binutils as does not produce linked executables.

(The default output filename for ld foo.o or gcc / clang without -c is also a.out, but don't be fooled by the name.)

You can use gcc -v -c foo.s to show the as command line it uses, including the -o option. (clang has a built-in assembler, so it won't run a separate as command, but the gcc front-end truly does just run as to assemble asm source files. And without -c, then runs ld (via collect2) to link the object file into an executable.)

e.g. on my x86-64 GNU/Linux system:

$ cat > foo.s
mov $231, %eax             # __NR_exit_group
syscall
$ as foo.s
$ file a.out
a.out: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
$ ld a.out -o exit
ld: warning: cannot find entry symbol _start; defaulting to 0000000000401000
$ ls -l exit a.out 
-rw-r--r-- 1 peter peter  664 Mar 22 08:23 a.out
-rwxr-xr-x 1 peter peter 4632 Mar 22 08:23 exit
$ file exit
exit: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped

$ ./a.out
bash: ./a.out: Permission denied
$ ./exit
$ strace ./exit 
execve("./exit", ["./exit"], 0x7ffc72823fc0 /* 55 vars */) = 0
exit_group(0)                           = ?
+++ exited with 0 +++
$ as --version
GNU assembler (GNU Binutils) 2.35.1
...
This assembler was configured for a target of `x86_64-pc-linux-gnu'.
$ ld --version
GNU ld (GNU Binutils) 2.35.1
...
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • I assumed it's a linked file because the result file `a.out` is runnable using `./a.out`. – Rui Mar 22 '21 at 12:45
  • @Rui: Like I demonstrated, on my Arch GNU/Linux system, that is *not* the case. It doesn't have exec permission, and it's an ELF "relocatable" not "executable" or "shared object"/"PIE executable". Even if I chmod it, I get `Exec format error` on trying to run it. What kind of system are you on? – Peter Cordes Mar 22 '21 at 12:51
  • I see `relocatable` in `file a.out` too, but in my case its runnable. I am at ubuntu. Is it because the format relocatable and executable are so close that sometimes relocatable are also runnable? – Rui Mar 22 '21 at 13:06
  • @Rui: They're both ELF, but a relocatable is not runnable by any mechanism I'm aware of: it hasn't been linked yet so it isn't ready to run. Only thing I can think of is some kind of `binfmt_misc` setup that transparently links it into an executable on the fly. – Peter Cordes Mar 22 '21 at 13:11
  • @Rui: Are you *sure* you're not accidentally running some other `a.out` that is a linked executable? Does `readelf -a a.out` show any "program headers"? ELF Program Headers are what's necessary for the kernel's program-loader to map it into virtual address space of a process. In my a.out, I see `There are no program headers in this file.` (Only section headers; that's why it works as linker input.) – Peter Cordes Mar 22 '21 at 13:16
  • Sorry, I didn't remember the exact result of `file a.out`, it's an executable. `gcc -v -c hello.s` helped me find out `as --64 -o hello.o hello.s` is the result. I have doubt checked the result, I am sure this answer is right. Thank you for your help. – Rui Mar 22 '21 at 13:25
  • 2
    Oh, you are totally right, I have mixed up the result!!!!I am very sorry. `as` does not produce executable file!!! – Rui Mar 22 '21 at 13:37
  • @Rui: The `as` defaults are `--64 -o a.out`, so GCC is just being explicit about it, and setting a different output filename. If you had an executable, not relocatable, a.out, it was probably left over from running `gcc hello.s` (without `-c`), or from running `ld a.out` which reads `a.out` (an object file) and writes a new `a.out` (an executable). (Except that doesn't work because `ld a.out` truncates a.out before it reads it, so you get an "executable" with no .text) – Peter Cordes Mar 22 '21 at 13:38
  • 2
    Note that OP's file is named `main.S`, so the preprocessor might need to run. – fuz Mar 22 '21 at 13:43
0

The most simple way, use clang -v -fno-integrated-as -c main.c and get the gas command line from its output.

Zilog80
  • 2,534
  • 2
  • 15
  • 20
  • It shows clang's command line, I don't see a command line start with `as`. – Rui Mar 22 '21 at 12:53
  • @Rui: This would only work with `gcc -v -c foo.s` (or foo.c), not clang. clang has a built-in assembler so it doesn't need to run `as` on it. – Peter Cordes Mar 22 '21 at 13:17
  • If you've llvm clang, you can tell it to not use its integrated AS with `-fno-integrated-as`. By default, LLVM uses its proper integrated assembler. – Zilog80 Mar 22 '21 at 13:20
  • @Zilog80: The OP is looking for a command to assemble a `.s` into a `.o`. So `clang -S` is the answer to a different question. `clang -c foo.s` is a valid answer (given clang's built-in assembler, it works on its own without having to fork off an `as`). – Peter Cordes Mar 22 '21 at 13:37
  • @Peter Cordes The `clang -S` here is to show a way to get an assembler source from the C source with syntax choice. But it's true that the -llvm isn't directly related to the question, i'll remove my edit. – Zilog80 Mar 22 '21 at 13:41
  • Yes, I know what `-S` does, that's how I know it's not an answer to the question "how to assemble an existing `.s`". Yeah, it's a useful related thing, which you could leave in your answer if you explain exactly what it does, although that's covered by Q&As like [How to remove "noise" from GCC/clang assembly output?](https://stackoverflow.com/q/38552116) and [How to generate assembly code with clang in Intel syntax?](https://stackoverflow.com/q/10990018) – Peter Cordes Mar 22 '21 at 13:42
  • 1
    @PeterCordes As it's already covered in other Q&As, -llvm was then just noise in the answer. – Zilog80 Mar 22 '21 at 13:53
  • 1
    A good solution. `no-integrated-as` is a bit hard to find in the sea of options clang offered. – Rui Mar 22 '21 at 13:59