Context
I'm working through some examples in a book by Johnathan Bartlett titled "Learn to Program with Assembly" (2021). The author assumes a linux environment. I'm on OSX (Monterey). He's using gcc. I've got clang (v 13.1.6). In chapter 7 the author introduces laying out data records.
To facilitate this, he uses the .equ directive to define some constants in a file titled persondata.s which happens to only contain a data segment. For example:
# Describe the components of the struct
.globl WEIGHT_OFFSET, HAIR_OFFSET, HEIGHT_OFFSET, AGE_OFFSET .equ WEIGHT_OFFSET, 0
.equ HAIR_OFFSET, 8
.equ HEIGHT_OFFSET, 16
.equ AGE_OFFSET, 24
In another file, tallest.s, he makes use of the HEIGHT_OFFSET constant to access the height of a person record. This file has only a text segment.
movq HEIGHT_OFFSET(%rbx), %rax
The Problem
When I assemble tallest.s using the built-in tools on OSX, the assembler complains that I'm trying to use 32-bit absolute addressing in 64-bit mode.
The Question
How is this supposed to work on OSX? How am I supposed to make use of .equ defined constants?
Things I Tried
If I merge these two files into one file, then assembler doesn't complain. It treats HEIGHT_OFFSET as the constant that it is.
I presume the idea is to have constants defined along with the data, and then make use of those constants in code to avoid 'magic numbers'. Sounds like a good idea.
I tried assembling, linking, and running this code using the book's docker image (johnnyb61820/linux-assembly). It works. No complaints. Some details
# as -v
GNU assembler version 2.31.1 (x86_64-linux-gnu) using BFD version (GNU Binutils for Debian) 2.31.1
^C
# ld -v
GNU ld (GNU Binutils for Debian) 2.31.1
# uname -a
Linux eded2adb9c06 5.10.124-linuxkit #1 SMP Thu Jun 30 08:19:10 UTC 2022 x86_64 GNU/Linux
So it works as written under that set-up. Just not under my set-up which is clang (v 13.1.6).
Based on the fact that this works in the linuxkit docker image, I thought to install gcc via homebrew on my machine. This got me version 12.2.0 of gcc, which I used to try and compile/link my files. It also thinks HEIGHT_OFFSET is a problem due to 32-bit absolute addressing in 64-bit mode.
Based on the output of name -a in the docker image, I'm guessing it is 64 bit. Linux eded2adb9c06 5.10.124-linuxkit #1 SMP Thu Jun 30 08:19:10 UTC 2022 x86_64 GNU/Linux
Oddly enough, it doesn't complain about 32-bit absolute addressing not being supported. Under OSX, I had to make everything rip-relative to access any static-data (true for both gcc and clang). Makes me wonder what it is doing with these addresses.
As a possibly final note, under OSX yasm also doesn't like me using .equ defined constants from another file. It complains about wanting to make use of "32 bit absolute relocations" in 64 bit mode. GCC (12.2.0) and llvm-mc (13.0.1) also take issue with the HEIGHT_OFFSET constant.
Related
I need to use the TCC compiler to link object files generated by GCC. However, GCC in MinGW outputs object files in COFF format, and TCC only supports the ELF format. How can I make GCC generate ELF object files?
$ cat test.c
int main(void)
{
return 0;
}
$ gcc -c test.c
$ file test.o
test.o: MS Windows COFF Intel 80386 object file
$ tcc -c test.c
$ file test.o
test.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped
However, GCC in MinGW outputs object files in COFF format
GCC can be configured to generate various outputs (including ELF) regardless of which host it runs on.
That is, a GCC running on Linux could be configured to generate COFF, and a GCC running on Windows could be configured to generate ELF32 or ELF64, for various processors (e.g. x86, or SPARC, or MIPS).
A compiler that runs on one kind of host, but generates code for a different kind, is called a cross-compiler.
TCC only supports the ELF format
This is not a meaningful statement: it could mean that you want GCC to generate ELF32 for i686 Linux, or ELF64 for SPARC Solaris, or any number of other processor/os/bit combinations.
You should figure out what target processor and operating system you want to run your final executable on, and then build (non-trivial) or download appropriate cross-compiler from Windows to that target.
file test.o
test.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped
Ok, you want Windows to Linux/i386/ELF32 cross-compiler.
strip might help. strip accepts various object file formats for input and output type (the bfdname). strip --info for the supported formats.
strip -o outputname -O elf32-i386 objfile Doing so on a 64 bit executable, converted to 32bit control headers will lead to nothing but crash, so pick your output form carefully. Make sure you aren't changing assumed bitwidths / endians along with headers.
Not running MinGW, so, not tested, may not work for your needs, or worse, may jump and catch fire.
You want your compiler (MinGW) to generate binaries that are not of the type usable for your host system (Windows). This is called cross-compiling, and it is a somewhat involved subject -- because to create complete executables you will also need the various libraries: standard libraries, target OS libraries, third-party libraries... so it is not merely the subject of "how do I get the compiler to create ELF", but also "how do I get the whole supporting cast of ELF libs so I can link against them?".
OSDev has quite extensive documentation on the subject of setting up a cross-compiler; however, since you did not tell us what exactly your problem is, it is difficult to advise you further.
If what you want is generating Linux binaries, my advise would be to not bother with cross-compilation (which is a tricky subject -- and much better supported the other way around, i.e. targeting Windows from Linux), but rather install a Linux distribution in parallel to your Windows, and work natively with that.
This gdb was installed via Homebrew on my OSX.
I wonder why gdb doesn't work on this file(I was playing pwn)on my OSX, while I can run it on Kali linux through VirtualBox.
I saw some people mentioned "Apple version gdb", is that the problem?
And how do I solve this?
I searched for answer quite a while and even asked my proffessor, please give me a hand!
➜ file bof
bof: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV),
dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.24,
BuildID[sha1]=ed643dfe8d026b7238d3033b0d0bcc499504f273, not stripped
➜ gdb bof
GNU gdb (GDB) 8.0
Copyright (C) 2017 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
<http://gnu.org/licenses/gpl.html>
.
.
.
"/Users/me/Desktop/test/bof": not in executable format: File format not recognized
(gdb)
This gdb was installed via Homebrew on my OSX.
...
bof: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV),
dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.24,
There are many ways to configure gdb. The default -- if you don't pass any special options to configure -- is to configure in just what is needed for the host platform.
In this case, probably what has happened is that your gdb is configured for OSX -- meaning Mach-O and not ELF -- and so gdb can't read ELF files. You can test this theory by typing set gnutarget <TAB> <TAB> at the gdb prompt (the tabs will cause completion, which is the only way I know of to list what was compiled in here). Alternatively, you can try show configuration, though that just says what options were passed to configure, and so it needs interpretation.
One simple way to get out of this is to reconfigure with --enable-targets=all. Then gdb will be able to read ELF files and other things as well.
I am trying to boot a custom kernel on Xeon-phi instead of the default Linux kernel. At this link, I found a way to cross compile my kernel which compiles successfully using k1om-mpss-linux-gcc cross compiler. Is cross compiling enough ? I get the error
mykernel.img is not a k1om Linux bzImage
Edit:
So, I used /usr/linux-k1om-4.7/bin/x86_64-k1om-linux-gcc compiler to compile a simple helloworld.c program and the kernel source. I get two different types of results for objdump -f on the executables.
for helloworld.c:
hello: file format elf64-k1om
architecture: k1om, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
start address 0x0000000000400400
for mykernel:
mykernel: file format elf32-i386
architecture: i386, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
start address 0x0010000c
I compiled using the same compiler, yet they show different architectures. What is the reason for this ?
The first thing to do is figure out what mykernel.img is. Try running file on it.
$ file /opt/mpss/3.4/sysroots/k1om-mpss-linux/boot/vmlinux-2.6.38.8+mpss3.4
/opt/mpss/3.4/sysroots/k1om-mpss-linux/boot/vmlinux-2.6.38.8+mpss3.4: ELF 64-bit LSB executable, version 1 (SYSV), statically linked, BuildID[sha1]=0xa4c16ee85c11aca4e78dc4ae46d3827fb74289c1, not stripped
$ objdump -f /opt/mpss/3.4/sysroots/k1om-mpss-linux/boot/vmlinux-2.6.38.8+mpss3.4
/opt/mpss/3.4/sysroots/k1om-mpss-linux/boot/vmlinux-2.6.38.8+mpss3.4: file format elf64-k1om
architecture: k1om, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
start address 0x0000000001000000
The answer to your original question - no, unfortunately, it is not as simple as just cross-compiling. There were a number of changes made to the kernel that comes with the MPSS. I don't know all the changes but a big one that I do know is that they had to add support for the larger register set on the coprocessor in order to be able to save state on a context switch.
As to why the file format is elf32-i386 instead of elf32-k1om -
The web site you referenced referred to recompiling the kernel that came with the MPSS after possibly make a few changes in the files. You'll notice that they also copied over a configuration file for the installed version of the kernel. So they had all the files to remake the kernel exactly as it had been made.
I suspect that, in your case, either a) there was a configuration script of some sort in your source directory that picked up the architecture you were running on and caused confusion when the makefile ran or b) your makefile had no idea what k1om was. In either case, it fell back to what it believed to the the lowest common denominator i386. As I say, this is just a suspicion on my part but a careful reading of your makefiles should lead to the answer.
I have an ARM machine that runs Linux (BusyBox).
# uname -a
# Linux XXXXXXXX 2.6.28 #1 PREEMPT Fri Sep 26 22:47:38 UTC 2014 armv5tel GNU/Linux
I've cross-compiled a simple program on my Ubuntu 32-bit desktop:
./configure --host=arm-linux-gnueabi LDFLAGS="-static"
make
But when I try to run it on the ARM machine, it gives me Segmentation Fault error.
Program is super simple:
#include <stdio.h>
int main()
{
printf("Hello, World!");
return 0;
}
Here are a few things I've already tried/checked:
I've checked md5 hashes on both machines to eliminate the possibility that something went wrong at the time of copying an executable over the network
Stripped the executable with arm-linux-gnueabi-strip. I was comparing my executable with another executable that was already in the target machine with file:
# file my_program
# my_program: ELF 32-bit LSB executable, ARM, version 1 (SYSV), statically linked, for GNU/Linux 2.6.31, BuildID[sha1]=0x4b1f2773e54b141d5157b86f0f10438a372625c9, stripped
# file their_program
# their_program: ELF 32-bit LSB executable, ARM, version 1 (GNU/Linux), statically linked, stripped
What am I doing wrong?
Apparently my cross-compile toolchain was not the right one.
I ended up using crosstool-ng. Btw it's very simple to use and a great tool, all you have to do is to choose the right toolchain for your device.
I have built an arm-unknown-linux-uclibcgnueabi toolchain with crosstool-ng, which solved my problem.
I have a 64-bit system, but gcc is 32-bits and when I do
>./gcc -c foobar.c
it makes foobar.o which is 64-bits. OK, but how does it know to do that? Based on what environment setting does it know to produce 64-bit object, and where is that documented??
Come to think about it, it is strange that it does that, is it not?? But file utility clearly says, gcc is 32 bits and foobar.o is 64 bits. ( I moved everything to the same directory so it would not be confused. )
I also checked the 3 dynamically linked libraries that it reads: libc, libm and libz and they are also all 32 bits.
To clarify, I don't want to know, how to make it do 32 bits. I want to know, what is it looking at now that it makes it do 64. That is my question, not how to force it the other way around.
When GCC is configured three different systems can be specified:
build: - the system where GCC is going to be built (probably not
relevant to your question)
host: - the system where GCC is going to
be executed (32 bit in your case)
target: the system where binaries, produced by GCC are going to be executed (64 bit in your case)
You can see how your GCC was configured by running:
gcc -v
command (look for --{build,host,target} options.