Z80 assembly storing a value in a register for longer time - z80

I have the following part of code:
ld a, 2
INIT: ld ix, AFIS
ld c, a
cp 2
jp z INIT2
call SCAN
INIT2: ld ix, AFIS2
call SCAN
INIT3: ld ix, AFIS3
ld c, a
cp 2
jp z INIT4
The problem is with this code ld c, a from INIT3. It is like the register "a" has been reset and cp 2 will be set as false. How I can store a value in a register for longer time?

Procedure SCAN can be changing anything it likes.
If you are not in control of SCAN and SCAN does not have a documented list of registers that it changes then you will need to keep the registers that are important for you safe.
Using the stack:
ld a,2
INIT:
ld ix,AFIS
ld c,a
cp 2
push af ; store value of register pair af on stack
jp z,INIT2
call SCAN
INIT2: ld ix,AFIS2
call SCAN
INIT3: ld ix,AFIS3
pop af ; get value of register pair af from stack - f = flags
; since comparison was identical, no need to recompare
jp z,INIT4
Using a memory location as a variable store:
ld a,2
INIT:
ld (var),a ; store it
ld ix,AFIS
ld c,a
cp 2
jp z,INIT2
call SCAN
INIT2: ld ix,AFIS2
call SCAN
INIT3: ld ix,AFIS3
ld a,(var) ; get it assuming scan does not need it
ld c,a
cp 2
jp z,INIT4
...
var: defb 0

Related

creating Linux i386 a.out executable shorter than 4097 bytes

I'm trying to create a Linux i386 a.out executable shorter than 4097 bytes, but all my efforts have failed so far.
I'm compiling it with:
$ nasm -O0 -f bin -o prog prog.nasm && chmod +x prog
I'm testing it in a Ubuntu 10.04 i386 VM running Linux 2.6.32 with:
$ sudo modprobe binfmt_aout
$ sudo sysctl vm.mmap_min_addr=4096
$ ./prog; echo $?
Hello, World!
0
This is the source code of the 4097-byte executable which works:
; prog.nasm
bits 32
cpu 386
org 0x1000 ; Linux i386 a.out QMAGIC file format has this.
SECTION_text:
a_out_header:
dw 0xcc ; magic=QMAGIC; Demand-paged executable with the header in the text. The first page (0x1000 bytes) is unmapped to help trap NULL pointer references.
db 0x64 ; type=M_386
db 0 ; flags=0
dd SECTION_data - SECTION_text ; a_text=0x1000 (byte size of .text; mapped as r-x)
dd SECTION_end - SECTION_data ; a_data=0x1000 (byte size of .data; mapped as rwx, not just rw-)
dd 0 ; a_bss=0 (byte size of .bss)
dd 0 ; a_syms=0 (byte size of symbol table data)
dd _start ; a_entry=0x1020 (in-memory address of _start == file offset of _start + 0x1000)
dd 0 ; a_trsize=0 (byte size of relocation info or .text)
dd 0 ; a_drsize=0 (byte size of relocation info or .data)
_start: mov eax, 4 ; __NR_write
mov ebx, 1 ; argument: STDOUT_FILENO
mov ecx, msg ; argument: address of string to output
mov edx, msg_end - msg ; argument: number of bytes
int 0x80 ; syscall
mov eax, 1 ; __NR_exit
xor ebx, ebx ; argument: EXIT_SUCCESS == 0.
int 0x80 ; syscall
msg: db 'Hello, World!', 10
msg_end:
times ($$ - $) & 0xfff db 0 ; padding to multiple of 0x1000 ; !! is this needed?
SECTION_data: db 0
; times ($$ - $) & 0xfff db 0 ; padding to multiple of 0x1000 ; !! is this needed?
SECTION_end:
How can I make the executable file smaller? (Clarification: I still want a Linux i386 a.out executable. I know that that it's possible to create a smaller Linux i386 ELF executable.) There is several thousands bytes of padding at the end of the file, which seems to be required.
So far I've discovered the following rules:
If a_text or a_data is 0, Linux doesn't run the program. (See relevant Linux source block 1 and 2.)
If a_text is not a multiple of 0x1000 (4096), Linux doesn't run the program. (See relevant Linux source block 1 and 2.)
If the file is shorter than a_text + a_data bytes, Linux doesn't run the program. (See relevant Linux source code location.)
Thus file_size >= a_text + a_data >= 0x1000 + 1 == 4097 bytes.
The combinations nasm -f aout + ld -s -m i386linux and nasm -f elf + ld -s -m i386linux and as -32 + ld -s -m i386linux produce an executable of 4100 bytes, which doesn't even work (because its a_data is 0), and by adding a single byte to section .data makes the executable file 8196 bytes long, and it will work. Thus this path doesn't lead to less than 4097 bytes.
Did I miss something?
TL;DR It doesn't work.
It is impossible to make a Linux i386 a.out QMAGIC executable shorter than 4097 bytes work on Linux 2.6.32, based on evidence in the Linux kernel source code of the binfmt_aout module.
Details:
If a_text is 0, Linux doesn't run the program. (Evidence for this check: a_text is passed as the length argument to mmap(2) here.)
If a_data is 0, Linux doesn't run the program. (Evidence for this check: a_data is passed as the length argument to mmap(2) here.)
If a_text is not a multiple of 0x1000 (4096), Linux doesn't run the program. (Evidence for this check: fd_offset + ex.a_text is passed as the offset argument to mmap(2) here. For QMAGIC, fd_offset is 0.)
If the file is shorter than a_text + a_data bytes, Linux doesn't run the program. (Evidence for this check: file sizes is compared to a_text + a_data + a_syms + ... here.)
Thus file_size >= a_text + a_data >= 0x1000 + 1 == 4097 bytes.
I've also tried OMAGIC, ZMAGIC and NMAGIC, but none of them worked. Details:
For OMAGIC, read(2) is used instead of mmap(2) within here, thus it can work. However, Linux tries to load the code to virtual memory address 0 (N_TXTADDR is 0), and this causes SIGKILL (if non-root and vm.mmap_min_addr is larger than 0) or SIGILL (otherwise), thus it doesn't work. Maybe the reason for SIGILL is that the page allocated by set_brk is not executable (but that should be indicated by SIGSEGV), this could be investigated further.
For ZMAGIC and NMAGIC, read(2) instead of mmap(2) within here if fd_offset is not a multiple of the page size (0x1000). fd_offset is 32 for NMAGIC, and 1024 for ZMAGIC, so good. However, it doesn't work for the same reason (load to virtual memory address 0).
I wonder if it's possible to run OMAGIC, ZMAGIC or NMAGIC executables at all on Linux 2.6.32 or later.

Unclear output by riscv objdump -d

Now I am trying to understand the RISC-V ISA but I have an unclear point about the machine code and assembly.
I have written a C code like this:
int main() {
return 42;
}
Then, I produced the .s file by this command:
$ /opt/riscv/bin/riscv64-unknown-linux-gnu-gcc -S 42.c
The output was:
.file "42.c"
.option nopic
.text
.align 1
.globl main
.type main, #function
main:
addi sp,sp,-16
sd s0,8(sp)
addi s0,sp,16
li a5,42
mv a0,a5
ld s0,8(sp)
addi sp,sp,16
jr ra
.size main, .-main
.ident "GCC: (g5964b5cd727) 11.1.0"
.section .note.GNU-stack,"",#progbits
Now, I run following command to produce an elf.
$ /opt/riscv/bin/riscv64-unknown-linux-gnu-gcc -nostdlib -o 42 42.s
So, a binary file is produced. I tried to read that by objdump like this:
$ /opt/riscv/bin/riscv64-unknown-linux-gnu-objdump -d 42
So the output was like this:
42: file format elf64-littleriscv
Disassembly of section .text:
00000000000100b0 <main>:
100b0: 1141 addi sp,sp,-16
100b2: e422 sd s0,8(sp)
100b4: 0800 addi s0,sp,16
100b6: 02a00793 li a5,42
100ba: 853e mv a0,a5
100bc: 6422 ld s0,8(sp)
100be: 0141 addi sp,sp,16
100c0: 8082 ret
What I don't understand is the meaning of the machine code in objdump output.
For example, the first instruction addi is translated into .....0010011 according to this page, (while this is not an official spec). However, the dumped hex is 1141. 1141 can only represent 2 bytes, but the instruction should be 32-bit, 4bytes.
I guess I am missing some points, but how should I read the output of objdump for riscv?
You can tell objdump to show compressed (16-bit) instructions by using -M no-aliases in this way
riscv64-unknown-elf-objdump -d -M no-aliases
In that case, instructions starting with c. are compressed ones.
Unfortunately that will also disable some other aliases, making the asm less nice to read if you're used to them. You can just look at the number of bytes (2 vs. 4) in the hexdump to see if it's a compressed instruction or not.

How can it be done that functions in .so file are automatically exported?

In Windows, to call a function in a DLL, the function must have an explicit export declaration. For example, __declspec(dllexport) or .def file.
Other than Windows, we can call a function in a .so(shared object file) even if the function has no export declaration. It is much easier for me to make .so than .dll in terms of this.
Meanwhile, I am curious about how non-Windows enables functions defined in .so be called by other programs without having explicit export declaration. I roughly guess that all of the functions in .so file are automatically exported, but I am not sure of it.
An .so file is conventionally a DSO (Dynamic Shared Object, a.k.a shared library) in unix-like OSes. You want to
know how symbols defined in such a file are made visible to the runtime loader
for dynamic linkage of the DSO into the process of some program when
it's executed. That's what you mean by "exported". "Exported" is a somewhat
Windows/DLL-ish term, and is also apt to be confused with "external" or "global",
so we'll say dynamically visible instead.
I'll explain how dynamic visibility of symbols can be controlled in the context of
DSOs built with the GNU toolchain - i.e. compiled with a GCC compiler (gcc,
g++,gfortran, etc.) and linked with the binutils linker ld (or compatible
alternative compiler and linker). I'll illustrate with C code. The mechanics are
the same for other languages.
The symbols defined in an object file are the file-scope variables in the C source code. i.e. variables
that are not defined within any block. Block-scope variables:
{ int i; ... }
are defined only when the enclosing block is being executed and have no permanent
place in an object file.
The symbols defined in an object file generated by GCC are either local or global.
A local symbol can be referenced within the object file where it's defined but
the object file does not reveal it for linkage at all. Not for static linkage.
Not for dynamic linkage. In C, a file-scope variable definition is global
by default and local if it is qualified with the static storage class. So
in this source file:
foobar.c (1)
static int foo(void)
{
return 42;
}
int bar(void)
{
return foo();
}
foo is a local symbol and bar is a global one. If we compile this file
with -save-temps:
$ gcc -save-temps -c -fPIC foobar.c
then GCC will save the assembly listing in foobar.s, and there we can
see how the generated assembly code registers the fact that bar is global and foo is not:
foobar.s (1)
.file "foobar.c"
.text
.type foo, #function
foo:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $42, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size foo, .-foo
.globl bar
.type bar, #function
bar:
.LFB1:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
call foo
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE1:
.size bar, .-bar
.ident "GCC: (Ubuntu 8.2.0-7ubuntu1) 8.2.0"
.section .note.GNU-stack,"",#progbits
The assembler directive .globl bar means that bar is a global symbol.
There is no .globl foo; so foo is local.
And if we inspect the symbols in the object file itself, with
$ readelf -s foobar.o
Symbol table '.symtab' contains 10 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS foobar.c
2: 0000000000000000 0 SECTION LOCAL DEFAULT 1
3: 0000000000000000 0 SECTION LOCAL DEFAULT 2
4: 0000000000000000 0 SECTION LOCAL DEFAULT 3
5: 0000000000000000 11 FUNC LOCAL DEFAULT 1 foo
6: 0000000000000000 0 SECTION LOCAL DEFAULT 5
7: 0000000000000000 0 SECTION LOCAL DEFAULT 6
8: 0000000000000000 0 SECTION LOCAL DEFAULT 4
9: 000000000000000b 11 FUNC GLOBAL DEFAULT 1 bar
the message is the same:
5: 0000000000000000 11 FUNC LOCAL DEFAULT 1 foo
...
9: 000000000000000b 11 FUNC GLOBAL DEFAULT 1 bar
The global symbols defined in the object file, and only the global symbols,
are available to the static linker for resolving references in other object files. Indeed
the local symbols only appear in the symbol table of the file at all for possible
use by a debugger or some other object-file probing tool. If we redo the compilation
with even minimal optimisation:
$ gcc -save-temps -O1 -c -fPIC foobar.c
$ readelf -s foobar.o
Symbol table '.symtab' contains 9 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS foobar.c
2: 0000000000000000 0 SECTION LOCAL DEFAULT 1
3: 0000000000000000 0 SECTION LOCAL DEFAULT 2
4: 0000000000000000 0 SECTION LOCAL DEFAULT 3
5: 0000000000000000 0 SECTION LOCAL DEFAULT 5
6: 0000000000000000 0 SECTION LOCAL DEFAULT 6
7: 0000000000000000 0 SECTION LOCAL DEFAULT 4
8: 0000000000000000 6 FUNC GLOBAL DEFAULT 1 bar
then foo disappears from the symbol table.
Since global symbols are available to the static linker, we can link a program
with foobar.o that calls bar from another object file:
main.c
#include <stdio.h>
extern int foo(void);
int main(void)
{
printf("%d\n",bar());
return 0;
}
Like so:
$ gcc -c main.c
$ gcc -o prog main.o foobar.o
$ ./prog
42
But as you've noticed, we do not need to change foobar.o in any way to make
bar dynamically visible to the loader. We can just link it as it is into
a shared library:
$ gcc -shared -o libbar.so foobar.o
then dynamically link the same program with that shared library:
$ gcc -o prog main.o libbar.so
and it's fine:
$ ./prog
./prog: error while loading shared libraries: libbar.so: cannot open shared object file: No such file or directory
...Oops. It's fine as long as we let the loader know where libbar.so is, since my
working directory here isn't one of the search directories that it caches by default:
$ export LD_LIBRARY_PATH=.
$ ./prog
42
The object file foobar.o has a table of symbols as we've seen,
in the .symtab section, including (at least) the global symbols that are available to the static linker.
The DSO libbar.so has a symbol table in its .symtab section too. But it also has a dynamic symbol table,
in it's .dynsym section:
$ readelf -s libbar.so
Symbol table '.dynsym' contains 6 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __cxa_finalize
2: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable
3: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTab
4: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
5: 00000000000010f5 6 FUNC GLOBAL DEFAULT 9 bar
Symbol table '.symtab' contains 45 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
...
...
21: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
22: 0000000000001040 0 FUNC LOCAL DEFAULT 9 deregister_tm_clones
23: 0000000000001070 0 FUNC LOCAL DEFAULT 9 register_tm_clones
24: 00000000000010b0 0 FUNC LOCAL DEFAULT 9 __do_global_dtors_aux
25: 0000000000004020 1 OBJECT LOCAL DEFAULT 19 completed.7930
26: 0000000000003e88 0 OBJECT LOCAL DEFAULT 14 __do_global_dtors_aux_fin
27: 00000000000010f0 0 FUNC LOCAL DEFAULT 9 frame_dummy
28: 0000000000003e80 0 OBJECT LOCAL DEFAULT 13 __frame_dummy_init_array_
29: 0000000000000000 0 FILE LOCAL DEFAULT ABS foobar.c
30: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
31: 0000000000002094 0 OBJECT LOCAL DEFAULT 12 __FRAME_END__
32: 0000000000000000 0 FILE LOCAL DEFAULT ABS
33: 0000000000003e90 0 OBJECT LOCAL DEFAULT 15 _DYNAMIC
34: 0000000000004020 0 OBJECT LOCAL DEFAULT 18 __TMC_END__
35: 0000000000004018 0 OBJECT LOCAL DEFAULT 18 __dso_handle
36: 0000000000001000 0 FUNC LOCAL DEFAULT 6 _init
37: 0000000000002000 0 NOTYPE LOCAL DEFAULT 11 __GNU_EH_FRAME_HDR
38: 00000000000010fc 0 FUNC LOCAL DEFAULT 10 _fini
39: 0000000000004000 0 OBJECT LOCAL DEFAULT 17 _GLOBAL_OFFSET_TABLE_
40: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __cxa_finalize
41: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable
42: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTab
43: 00000000000010f5 6 FUNC GLOBAL DEFAULT 9 bar
The symbols in the dynamic symbol table are the ones that are dynamically visible -
available to the runtime loader. You
can see that bar appears both in the .symtab and in the .dynsym of libbar.so.
In both cases, the symbol has GLOBAL in the bind ( = binding)
column and DEFAULT in the vis ( = visibility) column.
If you want readelf to show you just the dynamic symbol table, then:
readelf --dyn-syms libbar.so
will do it, but not for foobar.o, because an object file has no dynamic symbol table:
$ readelf --dyn-syms foobar.o; echo Done
Done
So the linkage:
$ gcc -shared -o libbar.so foobar.o
creates the dynamic symbol table of libbar.so, and populates it with symbols
the from global symbol table of foobar.o (and various GCC boilerplate
files that GCC adds to the linkage by defauilt).
This makes it look like your guess:
I roughly guess that all of the functions in .so file are automatically exported
is right. In fact it's close, but not correct.
See what happens if I recompile foobar.c
like this:
$ gcc -save-temps -fvisibility=hidden -c -fPIC foobar.c
Let's take another look at the assembly listing:
foobar.s (2)
...
...
.globl bar
.hidden bar
.type bar, #function
bar:
.LFB1:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
call foo
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
...
...
Notice the assembler directive:
.hidden bar
that wasn't there before. .globl bar is still there; bar is still a global
symbol. I can still statically link foobar.o in this program:
$ gcc -o prog main.o foobar.o
$ ./prog
42
And I can still link this shared library:
$ gcc -shared -o libbar.so foobar.o
But I can no longer dynamically link this program:
$ gcc -o prog main.o libbar.so
/usr/bin/ld: main.o: in function `main':
main.c:(.text+0x5): undefined reference to `bar'
collect2: error: ld returned 1 exit status
In foobar.o, bar is still in the symbol table:
$ readelf -s foobar.o | grep bar
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS foobar.c
9: 000000000000000b 11 FUNC GLOBAL HIDDEN 1 bar
but it is now marked HIDDEN in the vis ( = visibility) column of the output.
And bar is still in the symbol table of libbar.so:
$ readelf -s libbar.so | grep bar
29: 0000000000000000 0 FILE LOCAL DEFAULT ABS foobar.c
41: 0000000000001100 11 FUNC LOCAL DEFAULT 9 bar
But this time, it is a LOCAL symbol. It will not be available to the static
linker from libbar.so - as we saw just now when our linkage failed. And it is no longer in the
dynamic symbol table at all:
$ readelf --dyn-syms libbar.so | grep bar; echo done
done
So the effect of -fvisibility=hidden, when compiling foobar.c, is to make
the compiler annotate .globl symbols as .hidden in foobar.o. Then, when
foobar.o is linked into libbar.so, the linker converts every global hidden
symbol to a local symbol in libbar.so, so that it cannot be used to resolve references
whenever libbar.so is linked with something else. And it does not add the hidden
symbols to the dynamic symbol table of libbar.so, so the runtime loader cannot
see them to resolve references dynamically.
The story so far: When the linker creates a shared library, it adds to the dynamic
symbol table all of the global symbols that are defined in the input object files and are not marked hidden
by the compiler. These become the dynamically visible symbols of the shared library. Global symbols are not
hidden by default, but we can hide them with the compiler option -fvisibility=hidden. The visibility
that this option refers to is dynamic visibility.
Now the ability to remove global symbols from dynamic visibility with -fvisibility=hidden
doesn't look very useful yet, because it seems that any object file we compile with
that option can contribute no dynamically visible symbols to a shared library.
But actually, we can control individually which global symbols defined in an object file
will be dynamically visible and which will not. Let's change foobar.c as follows:
foobar.c (2)
static int foo(void)
{
return 42;
}
int __attribute__((visibility("default"))) bar(void)
{
return foo();
}
The __attribute__ syntax you see here is a GCC language extension
that is used to specify properties of symbols that are not expressible in the standard language - such as dynamic visibility. Microsoft's
declspec(dllexport) is an Microsoft language extension with the same effect as GCC's __attribute__((visibility("default"))),
But for GCC, global symbols defined in an object file will possess __attribute__((visibility("default"))) by default, and you
have to compile with -fvisibility=hidden to override that.
Recompile like last time:
$ gcc -fvisibility=hidden -c -fPIC foobar.c
And now the symbol table of foobar.o:
$ readelf -s foobar.o | grep bar
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS foobar.c
9: 000000000000000b 11 FUNC GLOBAL DEFAULT 1 bar
shows bar with DEFAULT visibility once again, despite -fvisibility=hidden. And if we relink libbar.so:
$ gcc -shared -o libbar.so foobar.o
we see that bar is back in the dynamic symbol table:
$ readelf --dyn-syms libbar.so | grep bar
5: 0000000000001100 11 FUNC GLOBAL DEFAULT 9 bar
So, -fvisibility=hidden tells the compiler to mark a global symbol as hidden
unless, in the source code, we explicitly specify a countervailing dynamic visibility
for that symbol.
That's one way to select precisely the symbols from an object file that we wish
to make dynamically visible: pass -fvisibility=hidden to the compiler, and
individually specify __attribute__((visibility("default"))), in the source code, for just
the symbols we want to be dynamically visible.
Another way is not to pass -fvisibility=hidden to the compiler, and indvidually
specify __attribute__((visibility("hidden"))), in the source code, for just the
symbols that we don't want to be dynamically visible. So if we change foobar.c again
like so:
foobar.c (3)
static int foo(void)
{
return 42;
}
int __attribute__((visibility("hidden"))) bar(void)
{
return foo();
}
then recompile with default visibility:
$ gcc -c -fPIC foobar.c
bar reverts to hidden in the object file:
$ readelf -s foobar.o | grep bar
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS foobar.c
9: 000000000000000b 11 FUNC GLOBAL HIDDEN 1 bar
And after relinking libbar.so, bar is again absent from its dynamic symbol
table:
$ gcc -shared -o libbar.so foobar.o
$ readelf --dyn-syms libbar.so | grep bar; echo Done
Done
The professional approach is to minimize the dynamic API of
a DSO to exactly what is specified. With the apparatus we've discussed,
that means compiling with -fvisibility=hidden and using __attribute__((visibility("default"))) to
expose the specified API. A dynamic API can also be controlled - and versioned - with the GNU linker
using a type of linker script called a version-script: that is a
yet more professional approach.
Further reading:
GCC Wiki: Visibility
GCC Manual: Common Function Attributes -> visibility ("visibility_type")

Where is segment %fs for static elf images setup?

I'm trying to figure out how the %fs register is initialized
when creating a elf image by hand.
The simple snippet I'd like to run is:
.text
nop
movq %fs:0x28, %rax;
1: jmp 1b
Which should read at offset 0x28 in the %fs segment. Normally this is where the stack canary is stored. Because I create the elf image by hand the %fs segment is not setup at all by my code this fails expectedly(?) .
Here is how I create the elf image:
0000000000000000 <.text>:
0: 90 nop
1: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
8: 00 00
a: eb fe jmp 0xa
I create the .text segment via
echo 9064488b042528000000ebfe | xxd -r -p > r2.bin
Then I convert to elf:
ld -b binary -r -o raw.elf r2.bin
objcopy --rename-section .data=.text --set-section-flags .data=alloc,code,load raw.elf
At that point raw.elf contains my instructions. I then link with
ld -T raw.ld -o out.elf -M --verbose where raw.ld is:
OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
OUTPUT_ARCH(i386:x86-64)
ENTRY(_entry)
PHDRS {
phdr4000000 PT_LOAD;
}
SECTIONS
{
_entry = 0x4000000;
.text 0x4000000 : { raw.elf (.text) } :phdr4000000
}
I can now start out.elf with gdb:
gdb --args out.elf
and set a breakpoint at 0x4000000:
(gdb)break *0x4000000
(gdb)run
The first nop can be stepped via stepi, however the stack canary read mov %fs:0x28,%rax segfaults.
I suppose that is expected given that maybe the OS is not setting up %fs.
For a simple m.c: int main() { return 0; } program compiled with gcc --static m.c -o m I can read from %fs. Adding:
long can()
{
long v = 0;
__asm__("movq %%fs:0x28, %0;"
: "=r"(val)::);
return v;
}
lets me read from %fs - even though I doubt that %fs:28 is setup because ld.so is not run (it is a static image).
Question:
Can anyone point out where %fs is setup in the c runtime for static images?
You need to call arch_prctl with an ARCH_SET_FS argument before you can use the %fs segment prefix. You will have to allocate the backing store somewhere (brk, mmap, or an otherwise unused part of the stack).
glibc does this in __libc_setup_tls in csu/libc-tls.c for statically linked binaries, hidden behind the TLS_INIT_TP macro.

C++-Assembly linking on x86 / ubuntu - undefined reference to ThreadRoot, SWITCH

I am building Nachos source on Ubuntu 12.04
If we believe "lscpu" output, machine arch is x86. I am getting the following error at the last step of make:
$ make
g++ -m32 -P -I../network -I../filesys -I../userprog -I../threads -I../machine -I../lib -iquote -Dx86 -DLINUX -c ../threads/switch.S
g++ bitmap.o debug.o libtest.o sysdep.o interrupt.o stats.o timer.o console.o machine.o mipssim.o translate.o network.o disk.o alarm.o kernel.o main.o scheduler.o synch.o thread.o addrspace.o exception.o synchconsole.o directory.o filehdr.o filesys.o pbitmap.o openfile.o synchdisk.o post.o switch.o -m32 -o nachos
scheduler.o: In function `Scheduler::Run(Thread*, bool)':
/home/userx/nachos/NachOS-4.0/code/build.linux/../threads/scheduler.cc:133: undefined reference to `SWITCH'
thread.o: In function `Thread::StackAllocate(void ()(void), void*)':
/home/userx/nachos/NachOS-4.0/code/build.linux/../threads/thread.cc:345: undefined reference to `ThreadRoot'
/home/userx/nachos/NachOS-4.0/code/build.linux/../threads/thread.cc:356: undefined reference to `ThreadRoot'
collect2: ld returned 1 exit status
make: * [nachos] Error 1
$
Here is the switch.S that has the symbol defs --
/* We define two routines for each architecture:
*
* ThreadRoot(InitialPC, InitialArg, WhenDonePC, StartupPC)
<...>
#ifdef SOLARIS
.globl ThreadRoot
ThreadRoot:
#else
.globl _ThreadRoot
_ThreadRoot:
#endif
#ifdef x86
.text
.align 2
.globl ThreadRoot
.globl _ThreadRoot
_ThreadRoot:
ThreadRoot:
<...>
.globl SWITCH
.globl _SWITCH
_SWITCH:
SWITCH:
<...>
#endif
I have skipped the #ifdefs for more arch like DECMIPS, POWERPC, APPLEPOWERPC etc.
Yes, my env $PATH includes dir where switch.s resides :/home/userx/nachos/NachOS-4.0/code/threads/
Please let me know if any more info is needed to debug. Thanks a lot.
Try adding underscore in the C header file that have extern "C" SWITCH and ThreadRoot, and change too the .c file in where the error is. I mean use _SWITCH instead SWITCH and the same for ThreadRoot.

Resources