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