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"
Related
What is the correct gnu assembly syntax for doing the following:
.section .data2
.asciz "******* Output Data ********"
total_sectors_written: .word 0x0
max_buffer_sectors: .word ((0x9fc00 - $data_buffer) / 512) # <=== need help here
.align 512
data_buffer: .asciz "<The actual data will overwrite this>"
Specifically, I'm writing a toy OS. The code above is in 16-bit real mode. I'm setting up a data buffer that will be dumped back to the boot disk. I want to calculate the number of sectors there are between where data_buffer gets placed in memory, and the upper bound of that data buffer. (Address 0x9fc00 is where the buffer would run into RAM reserved for other purposes.)
I know I could write assembly code to calculate this; but, since it is a constant known at build time, I'm curious if I can get the assembler to calculate it for me.
I'm running into three specific problems:
(1) If I use $data_buffer I get this error:
os_src/boot.S: Assembler messages:
os_src/boot.S:497: Error: missing ')'
os_src/boot.S:497: Error: can't resolve `L0' {*ABS* section} - `$data_buffer' {*UND* section}
which I find confusing, because I should use $ when I want the memory address of a label, correct?
(2) If I use data_buffer instead of $data_buffer, I get this error:
os_src/boot.S: Assembler messages:
os_src/boot.S:497: Error: missing ')'
os_src/boot.S:497: Error: value of 653855 too large for field of 2 bytes at 31
make: *** [obj/boot/dd_test.o] Error 1
which seems to suggest that the assembler is complaining about the size of the intermediate value (which does not need to fit in a 16-bit word).
(3) And, of course, what's up with the missing ')'?
When you use expressions in GNU assembler they have to resolve to absolute values. GNU assembler isn't aware of what the origin point of the code will actually be at. That is what the linker is for. Because of that data_buffer absolute address isn't known until linking is done so it is considered relocatable. If you take an absolute value like 0x9fc00 and subtract a relocatable value from it you get a relocatable value. Relocatable values can't be used in constant (absolute) expressions.
All is not lost. The linker itself will know the absolute address once it arranges everything in memory. You seem to suggest you already use a linker script which means the work you have to do is minimal. You can use the linker to compute the value of max_buffer_sectors.
Your linker script will have a SECTIONS directive like:
SECTIONS
{
[your section contents here]
}
You can create a linker symbol max_buffer_sectors with something like:
SECTIONS
{
max_buffer_sectors = (0x9fc00 - (data_buffer)) / 512;
[your section contents here]
}
This will allow the linker to compute the size since it will know data_buffer absolute address in memory.
Your GNU assembly file will need a bit of tweaking:
.globl data_buffer
.section .data2
.asciz "******* Output Data ********"
total_sectors_written: .word 0x0
.align 512
data_buffer: .asciz "<The actual data will overwrite this>"
You'll notice I used .globl data_buffer. This exports the symbol and makes it global so that the linker can use it.
You can then use the symbol max_buffer_sectors in code like:
mov $max_buffer_sectors, %ax
My program works fine on Ubuntu.
It encounters error when I compile it with gcc on a Solaris SPARC system.
I have several pieces of code like:
printf("endian_convert: %s\n", endian_convert);
asm("movl $8, %esi\n\t"
"movl $.LC0, %edi\n\t"
"movl $0, %eax");
This is the error I get on SPARC:
gcc -g -Wall -Werror -pedantic -Wextra src/utfconverter.c -o bin/utf
/usr/ccs/bin/as: "/var/tmp//cc9czJEf.s", line 957: error: unknown "%"-symbol
/usr/ccs/bin/as: "/var/tmp//cc9czJEf.s", line 957: error: statement syntax
.......
/usr/ccs/bin/as: "/var/tmp//cc9czJEf.s", line 1058: error: unknown "%"-symbol
/usr/ccs/bin/as: "/var/tmp//cc9czJEf.s", line 1058: error: statement syntax
*** Error code 1 make: Fatal error: Command failed for target `utf'
So, the "%" symbol is considered as unknown on SPARC?
How can I fix this and make it working on SPARC?
(The original version of the question didn't mention that the errors were from a SPARC Solaris system, and just called it C90 because the old version of gcc installed on it defaulted to -std=c90, leading to error messages about things that are illegal in C90.)
Wait a minute, "works fine on Ubuntu but not on C90"? /usr/ccs/bin/as (in your screenshot) looks like Solaris. That + the hostname is a clue that this might be a SPARC machine, not x86 at all.
Obviously x86 assembly isn't valid SPARC assembly syntax. It's a different CPU architecture.
If you'd used gcc foo.c -S and looked at the resulting foo.s asm output file, you'd see that it was full of SPARC asm, except for text inserted literally by your asm statements.
SPARC syntax does use % decorators on register names, but the register names are different. e.g. add %i0, %i1, %o0 adds input registers i0 and i1, storing the result in output register o0. (Input as in function arg and output as in function result. SPARC uses a sliding window onto a large virtual register file that might or might not spill to memory, depending on whether the CPU microarchitecture is out of registers when the save instruction runs.)
Remember that these errors are from the Solaris assembler, not from gcc. You're using gcc but it's using the system assembler instead of the GNU assembler.
Anyway, I recommend rewriting your code into pure portable C, rather than using #ifdef __x86__ to keep using that inline asm, or writing a SPARC port of it.
BTW, your asm statement looks horrible. A different version of gcc might store a different constant at .LC0, breaking your code. More importantly, you're not using input/output constraints to tell the compiler what value is where. If you're assuming it's ok to set eax in asm inside a function, that's incorrect. The function can and will inline, and then your asm is just floating free in the middle of wherever your function inlined. See the end of this answer for links to some GNU C inline asm tutorials.
Also, you don't need inline asm to endian-convert. You will get better asm from using endian.h functions like uint32_t le32toh(uint32_t little_endian_32bits); which use gcc builtins or inline asm to get the compiler to make optimal assembly output itself.
See also https://gcc.gnu.org/wiki/DontUseInlineAsm, which applies even if you did know how to use it properly.
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.
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.
Hi while i cross compile an startup.s file
(arm-none-eabi-as file.s)
(*-gcc)
I am getting in each commentary line some errors
- junk at end of line, first unrecognized character is /
when i delete the // some comment lines i get
errors about undefined symbols even i defined them at beginning of the file.
anyone know whats wrong?
If you want to use macros or C comments, then you have to preprocess the source file with the C preprocessor. The C preprocessor removes comments and interprets macros. The GNU assembler should run the C preprocessor automatically if the source file name ends with .S, with an uppercase 'S'.
(arm) Assembler does not support // comments or defines, you have to use .equ and # for comments. If you let gcc parse it you can put C isms like that into your assembler. Personally I avoid such C isms and keep the assembler clean. if you cannot do that or need includes with defines for example let gcc pre-process the file before sending it to gas.