mac OSX Unknown pseudo-op: .type - macos

I have to write some assembler code. Therefore I installed gcc4.4 (per homebrew) and called gcc-4.4 -c asma.s, but it does not work as expected:
asma.s:3:Unknown pseudo-op: .type
asma.s:3:Rest of line ignored. 1st junk character valued 97 (a).
The first lines consist only of standard pseudo-ops!
.text
.globl asma
.type asma, #function
asma:
Do I have to install an alternative assembler?

.type is an ELF/COFF directive, while OSX uses Mach-O format. In most cases you can safely remove the line.

Related

Run intel no prefix x86-64 assembly on MacOS

As part of a class, I need to write assembly code with specific format. The teacher refers to it as "Intel syntax x86-64". I tried to compile it with the given command (gcc -O3 -o op sc.s) and despite working great on a linux PC it fails on a Mac. After some researches I found Mac OS doesn't support this syntax and following the advices from the teacher I tried to run Linux from a bootable USB key and on a Virtual Machine (using VirtualBox) but both fail due to keyboard compatibility issues. I searched a few online solution but none of them could compile the source code without problem. How can I run it without buying a new computer ? I would like to run this exact syntax if it's possible.
Thank you for reading me !
Here a exemple of code he gave us :
.intel_syntax noprefix
.data
msg: .asciz "Hello, world!\n"
.text
.global main
.type main, #function
main: PUSH RBP
MOV RBP, RSP
MOV RDI, offset flat:msg
CALL printf
MOV EAX, 0
POP RBP
RET
With can be compiled with gcc (shown in live) yet compiling it with gcc -o hw1 hw.s or gcc -o hw1 -masm=intel hw.s give me the following error :
hw.s:6:9: error: unknown directive
.type main, #function
^
hw.s:9:29: error: unknown token in expression
MOV RDI, offset flat:msg
Edit: Setting up an ssh server on the VM and connecting to the VM via the host terminal made things much easier with VirtualBox, see https://stackoverflow.com/a/10532299/5770818
I don't think there's a good solution on macOS. As far as I know, GNU binutils don't support the Mach binary format on macOS, which means you can't just use the same assembler as on Linux (gas).
The issue isn't only the syntax, in fact, the syntax as such is partially supported. You will also run into other platform-related differences. For example, the ".type" directive wouldn't be used on macOS, and symbol names are prefixed with an underscore.
If you have keyboard issues with VMs, I'd recommend setting up some server Linux distribution in the VM and then run it in headless mode. Access it by logging in with ssh. This way you interact with it through Terminal, and shouldn't have keyboard problems.
Docker might also be an option, since it actually runs Linux in a VM on macOS, but might be more work to figure out.
Anyway, if you're interested in a version of the code that works on macOS:
.intel_syntax noprefix
.data
msg: .asciz "Hello, world!\n"
.text
.global _main
_main: PUSH RBP
MOV RBP, RSP
LEA RDI, [RIP + msg]
CALL _printf
MOV EAX, 0
POP RBP
RET
I removed the ".type" line, added underscores to main and printf, and changed "MOV RDI, offset flat:msg" to "LEA RDI, [RIP + msg]".
Build with "clang -o hw1 hw1.s", no reason to pretend we're running gcc ;)
You're attempting to assemble a file using gas syntax, so you need to use an assembler that supports that -- either gas iteself, or something like yasm

Why doesn't the GCC assembly output generate a .GLOBAL for printf

I have a trivial example C program:-
#include <stdio.h>
int main()
{
printf("hello world!");
return 1;
}
I use the following command to compile it and generate assembly:-
riscv32-unknown-elf-gcc -S hello.c -o hello.asm
Which generates the following assembly: -
.file "hello.c"
.option nopic
.section .rodata
.align 2
.LC0:
.string "hello world!"
.text
.align 2
.globl main
.type main, #function
main:
addi sp,sp,-16
sw ra,12(sp)
sw s0,8(sp)
addi s0,sp,16
lui a5,%hi(.LC0)
addi a0,a5,%lo(.LC0)
call printf
li a5,1
mv a0,a5
lw ra,12(sp)
lw s0,8(sp)
addi sp,sp,16
jr ra
.size main, .-main
.ident "GCC: (GNU) 7.2.0"
There is an expected call printf line but because there is no implementation of the printf inside this assembly file I would have expected to see it request an external implementation with something like this...
.global printf
But there is no such line in the assembly. I thought that without the global directive it meant that the linker will only try and resolve it to labels inside this single assembly file. I thought that was the whole point of the global directive, so that all the labels are local to the single assembly file unless exported using .global for access from other object files or import from another object file by also using .global.
What am I missing here?
.global would mark a label in the current file as having global scope (available to other modules). Maybe you meant .extern. Although .extern can be used to say a label is external, the directive is actually ignored by GNU Assembler. From the manual:
.extern is accepted in the source program--for compatibility with other assemblers--but it is ignored. as treats all undefined symbols as external.
as = GNU assembler.
GNU assembler assumes that any label it doesn't know about in the current file is an external reference. It is up to the linker to determine if it is undefined or not. That is why you don't see any directive marking printf as being external. In GNU assembler it just isn't necessary.
Note: Part of the confusion may be in that assemblers like NASM/YASM require an explicit extern statement to denote that a symbol is not within the local module being assembled. Those assemblers will return with an error that a symbol was undefined. This is one difference between GNU Assembler and NASM/YASM.
The .global .directive doesn't import labels, as it is essentially export. It only marks labels in the current file as globally available to other modules. It is not used for importing labels from other modules. From the manual:
.global makes the symbol visible to ld. If you define symbol in your partial program, its value is made available to other partial programs that are linked with it. Otherwise, symbol takes its attributes from a symbol of the same name from another file linked into the same program.
Both spellings (‘.globl’ and ‘.global’) are accepted, for compatibility with other assemblers.
There is a .global main directive to mark main as global. Without it the linker will assume that main is essentially a static label specific to a module and not usable by other modules. The C runtime library needs access to main since main must be called as the last step of transferring control to the entry of your C code.

Dragonegg on Mac OS X Issues

I'm trying to get dragonegg built and running on my mac. Using LLVM 3.5 and gcc 4.8, from the homebrew package manager.
Compiling dragonegg in per the readme (GCC=/usr/local/bin/gcc-4.8 LLVM_CONFIG=/usr/local/bin/llvm-config-3.5 make) ends with this error:
Compiling Cache.cpp
/Users/aelberg/Development/dragonegg-3.5.0.src/src/Cache.cpp:243:15: error: no matching function for call to 'operator new'
WeakVH *W = new (&(*slot)->V) WeakVH(V);
^ ~~~~~~~~~~~~~
note: candidate function not viable: requires 1 argument, but 2 were provided
1 error generated.
make: *** [Cache.o] Error 1
This seems to relate to the libc++ vs. libstdc++ issues that have been a problem compiling on the mac. And dragonegg will compile with GCC=/usr/local/bin/gcc-4.8 LLVM_CONFIG=/usr/local/bin/llvm-config-3.5 LDFLAGS="-L/usr/local/lib/ -L/usr/lib -L/usr/local/lib/llvm-3.5/usr/lib" CXX="/usr/local/bin/clang++-3.5 -stdlib=libc++" CXXFLAGS="-I/usr/local/lib/llvm-3.5/include/c++/v1" make
However, when I attempt to use dragonegg to compile anything, I get this unfortunate set of errors:
$ /usr/local/bin/gcc-4.8 -fplugin=/usr/local/lib/dragonegg_483_35.so hello.c
/var/folders/s1/_v14lsc56tv44hm304m07vn40000gq/T//ccPKylId.s:2:Unknown pseudo-op: .macosx_version_min
/var/folders/s1/_v14lsc56tv44hm304m07vn40000gq/T//ccPKylId.s:2:Rest of line ignored. 1st junk character valued 49 (1).
/var/folders/s1/_v14lsc56tv44hm304m07vn40000gq/T//ccPKylId.s:9:Unknown pseudo-op: .cfi_startproc
/var/folders/s1/_v14lsc56tv44hm304m07vn40000gq/T//ccPKylId.s:12:Unknown pseudo-op: .cfi_def_cfa_offset
/var/folders/s1/_v14lsc56tv44hm304m07vn40000gq/T//ccPKylId.s:12:Rest of line ignored. 1st junk character valued 49 (1).
/var/folders/s1/_v14lsc56tv44hm304m07vn40000gq/T//ccPKylId.s:14:Unknown pseudo-op: .cfi_offset
/var/folders/s1/_v14lsc56tv44hm304m07vn40000gq/T//ccPKylId.s:14:Rest of line ignored. 1st junk character valued 37 (%).
/var/folders/s1/_v14lsc56tv44hm304m07vn40000gq/T//ccPKylId.s:17:Unknown pseudo-op: .cfi_def_cfa_register
/var/folders/s1/_v14lsc56tv44hm304m07vn40000gq/T//ccPKylId.s:17:Rest of line ignored. 1st junk character valued 37 (%).
/var/folders/s1/_v14lsc56tv44hm304m07vn40000gq/T//ccPKylId.s:72:Unknown pseudo-op: .cfi_endproc
$ /usr/local/bin/gcc-4.8 hello.c
$ ./a.out
Hello World
This, obviously, seems unlikely to involve any of the settings in the compiler flags used to create dragonegg, since they all relate to C++.
Any suggestions?
The solution I found is to tell dragonegg to use llvm's assembler rather than the system assembler by adding -specs=[path to integrated=as.specs]. Per dragonegg's documentation this should neither be necessary, nor work, but it does.

basic assembly not working on Mac (x86_64+Lion)?

here is the code(exit.s):
.section .data,
.section .text,
.globl _start
_start:
movl $1, %eax
movl $32, %ebx
syscall
when I execute " as exit.s -o exit.o && ld exit.o -o exit -e _start && ./exit"
the return is "Bus error: 10" and the output of "echo $?" is 138
I also tried the example of the correct answer in this question: Process command line in Linux 64 bit
stil get "bus error"...
First, you are using old 32-bit Linux kernel calling convention on Mac OS X - this absolutely doesn't work.
Second, syscalls in Mac OS X are structured in a different way - they all have a leading class identifier and a syscall number. The class can be Mach, BSD or something else (see here in the XNU source) and is shifted 24 bits to the left. Normal BSD syscalls have class 2 and thus begin from 0x2000000. Syscalls in class 0 are invalid.
As per §A.2.1 of the SysV AMD64 ABI, also followed by Mac OS X, syscall id (together with its class on XNU!) goes to %rax (or to %eax as the high 32 bits are unused on XNU). The fist argument goes in %rdi. Next goes to %rsi. And so on. %rcx is used by the kernel and its value is destroyed and that's why all functions in libc.dyld save it into %r10 before making syscalls (similarly to the kernel_trap macro from syscall_sw.h).
Third, code sections in Mach-O binaries are called __text and not .text as in Linux ELF and also reside in the __TEXT segment, collectively referred as (__TEXT,__text) (nasm automatically translates .text as appropriate if Mach-O is selected as target object type) - see the Mac OS X ABI Mach-O File Format Reference. Even if you get the assembly instructions right, putting them in the wrong segment/section leads to bus error. You can either use the .section __TEXT,__text directive (see here for directive syntax) or you can also use the (simpler) .text directive, or you can drop it altogether since it is assumed if no -n option was supplied to as (see the manpage of as).
Fourth, the default entry point for the Mach-O ld is called start (although, as you've already figured it out, it can be changed via the -e linker option).
Given all the above you should modify your assembler source to read as follows:
; You could also add one of the following directives for completeness
; .text
; or
; .section __TEXT,__text
.globl start
start:
movl $0x2000001, %eax
movl $32, %edi
syscall
Here it is, working as expected:
$ as -o exit.o exit.s; ld -o exit exit.o
$ ./exit; echo $?
32
Adding more explanation on the magic number. I made the same mistake by applying the Linux syscall number to my NASM.
From the xnu kernel sources in osfmk/mach/i386/syscall_sw.h (search SYSCALL_CLASS_SHIFT).
/*
* Syscall classes for 64-bit system call entry.
* For 64-bit users, the 32-bit syscall number is partitioned
* with the high-order bits representing the class and low-order
* bits being the syscall number within that class.
* The high-order 32-bits of the 64-bit syscall number are unused.
* All system classes enter the kernel via the syscall instruction.
Syscalls are partitioned:
#define SYSCALL_CLASS_NONE 0 /* Invalid */
#define SYSCALL_CLASS_MACH 1 /* Mach */
#define SYSCALL_CLASS_UNIX 2 /* Unix/BSD */
#define SYSCALL_CLASS_MDEP 3 /* Machine-dependent */
#define SYSCALL_CLASS_DIAG 4 /* Diagnostics */
As we can see, the tag for BSD system calls is 2. So that magic number 0x2000000 is constructed as:
// 2 << 24
#define SYSCALL_CONSTRUCT_UNIX(syscall_number) \
((SYSCALL_CLASS_UNIX << SYSCALL_CLASS_SHIFT) | \
(SYSCALL_NUMBER_MASK & (syscall_number)))
Why it uses BSD tag in the end, probably Apple switches from mach kernel to BSD kernel. Historical reason.
Inspired by the original answer.

Unknown pseudo-op: .global

I'm trying to compile a simple operating system code we got on OS class. It works fine under Ubuntu but I'd like to compile it on OS X. The error I get is:
[compiling] arch/i386/arch/startup.S ...
arch/i386/arch/startup.S:8:Unknown pseudo-op: .extern
arch/i386/arch/startup.S:8:Rest of line ignored. 1st junk character valued 107 (k).
arch/i386/arch/startup.S:11:Expected comma after segment-name
arch/i386/arch/startup.S:13:Unknown pseudo-op: .global
arch/i386/arch/startup.S:13:Rest of line ignored. 1st junk character valued 97 (a).
This is the
source code of that file, and here is the makefile
So if anyone have an idea what to do I would appreciate it :)
As you're compiling using OS/X you'll be using X-Code's ancient version of as. This means you'll have to put up with some slightly older syntax. This other answer covers some of these problems.
At very least you're going to need to replace .global with .globl. You can remove .extern as all symbols are treated as external by default. For the section definition you should consult the gas manual; I believe the assembler is asking you to define the section flags.
I think it should be ".globl" not ".global"

Resources