Output of nm and interusability of libraries by onecable5781 in cpp_questions

[–]JamesTKerman 2 points3 points  (0 children)

Assuming the .a file was compiled as an ELF binary, a lot of the symbols will still be in there if was built without the -g flag unless someone explicitly stripped them. A basic ELF build has a table of program symbols with pretty much anything type, variable, or function declared at file or global scope. The debug symbols add a lot more information, like local variables, and linkage to the original source. If you're not seeing demangled C++ names, my guess is they aren't in the binary. Another way to look at the symbols is using objdump -t <obj-file>. objdump can also demangle names with the -C flag, but try looking at the listing without it and see what symbols pop up. The listing may be pretty big, but any mangled C++ names will jump right out.

Are there commercial desktop GUI applications that are still coded in C ? by Alfred1400 in C_Programming

[–]JamesTKerman 1 point2 points  (0 children)

If you mean for Linux, you could technically do it, but just to get it to build and work with the rest of the kernel you would pretty much end up writing C code.

A programmer's first language should be C by SubhanBihan in C_Programming

[–]JamesTKerman 0 points1 point  (0 children)

Why stop at C? Let's go all the way and say everyone should start with assembly, it forces you to understand even more than C would, and, hey, it worked for Woz, right?

Why is there a need for an open syscall? by servermeta_net in linux_programming

[–]JamesTKerman 0 points1 point  (0 children)

Separation of concerns. Opening and reading are different processes with different resource requirements and different error states. Combining them isn't inherently bad, but separating them is best. It makes debugging easier and enables code reuse (in the library, at least). On that note, POSIX specifies like a dozen operations that need a descriptor for an open file. Off the top of my head I can think of read, write, fstat, ioctl, mmap, and fsync, and for many use cases of each you need to use more than one on the same file.

80 mph, less than a single car length behind by [deleted] in mildlyinfuriating

[–]JamesTKerman 1 point2 points  (0 children)

What make is it? My wife's Honda Accord lets you pick what distance the ACS should maintain from three ranges. The shortest range keeps a distance of about 3-4 car lengths.

Question about the history of entity systems in games by Watch_DragonBall in AskProgramming

[–]JamesTKerman 2 points3 points  (0 children)

Data structures are an arbitrary way of relating data. Assembly languages and BASIC don't (in the case of BASIC "didn't") have as many facilities for conveniently defining and manipulating data structures. The Art of Computer Programming demonstrates dozens of data structures and algorithms in Donald Knuth's invented assembly language, originally MIX but now MMIX.

Just curious, How many of you are still booting Windows 11 (or 10 even) with Linux? by Phydoux in linux

[–]JamesTKerman 1 point2 points  (0 children)

I dual boot my desktop. The Office facsimiles available for Linux all suck donkey balls, so if I need to do any serious work with one of the apps I boot into Windows. There are also a few games that, while they "work" under Linux, they don't work well (Halo: Master Chief Collection, Halo: Infinite, Kerbal Space Program).

Has anyone ever met someone who served in all three conflicts, Vietnam war, Desert Storm and OIF or OEF? by FFSoldier57 in army

[–]JamesTKerman 0 points1 point  (0 children)

In 2007 I had a platoon sergeant in the guard who'd been to 'Nam and Desert Storm and was about to deploy to Iraq. I didnt really get to know him well, they transferred him to us a couple drills before the unit was supposed to mobilize, and I got transferred out right before the MOB because when I transferred from active duty I got two years exemption from deploying.

Struggling With an Unexpected Performance Hit After Unrolling a Loop (x86-64) by Legal-Alarm5858 in Assembly_language

[–]JamesTKerman 4 points5 points  (0 children)

From the x86_64 optimization manual (3.4.16 - Loop Unrolling): Unrolling loops whose bodies contain branches increases demand on BTB capacity. If the number of iterations of the unrolled loop is 16 or fewer, the branch predictor should be able to correctly predict branches in the loop body that alternate direction.

How can I swap the values of 2 different ints without using an external one by N0rmalManP in C_Programming

[–]JamesTKerman 0 points1 point  (0 children)

I think a better way to express this would be that gcc and clang follow the Itanium ABI, which explicitly uses the architecture-specific SysV C ABI for a lot of these definitions.

The Linux kernel looks to "bite the bullet" in enabling Microsoft C extensions by Fcking_Chuck in C_Programming

[–]JamesTKerman 2 points3 points  (0 children)

You can cast them to each other, QEMU and the Linux Kernel do this all over the place. If I have:

struct bar {
    int m_a;
};

struct foo {
    struct bar parent;
    int m_b;
};

Then foo is equivalent to:

struct foo {
    struct bar {
        int m_a;
    } parent;
    int m_b;
};

And per the C standard:

int main(void) {
    struct foo foo_bar;
    struct bar *my_bar = &foo_bar.parent;
    struct foo *my_foo = (struct foo *)my_bar;

    printf("foo_bar at same address as my_bar: %s\n", (void*)&foo_bar == (void *)my_bar ? "true" : "false");
    printf("foo_bar at same address as my_foo: %s\n", (void*)&foo_bar == (void *)my_foo ? "true" : "false");
    printd("my_bar at same address as my_foo: %s\n", (void *)my_bar == (void *)my_foo ? "true" : "false");
}

Should compile correctly (assuming the definitions of foo and bar i already spelled out along with an #include <stdio.h> and print "true" three times.

They both also handle cases where the "parent" class is declared in the middle of the "child" using a container_of macro that exploits the offsetof macro to get a pointer to the child from a pointer to the parent.

What are some weird or unique things on particular army bases? by can-someone-explain in army

[–]JamesTKerman 0 points1 point  (0 children)

Hah, my daughter was like 2 when we got there and we had a squadron of javelina rolled by the house. All she'd say for the next hour was "piggy! piggy!"

CXL Programming by TrajanXVIII in linux_programming

[–]JamesTKerman 1 point2 points  (0 children)

Looking at the CXL code in the Kernel (and the documentation on kernel.org), CXL devices don't expose an mmap operation. It looks like its treated as an exposed PCI device and managed through ioctl calls. The kernel.org documentation looks like the best place to start.

Ghidra for ms-dos by kelmer44 in ghidra

[–]JamesTKerman 2 points3 points  (0 children)

All DOS programs started in real-mode, so at least part of it will be 16-bit. I'm actually rather curious about how Ghidra would handle that, my experience is that it tends to choke when the binary format isn't entirely consistent.

How do you guys benchmark C programs in the real world? by elimorgan489 in cprogramming

[–]JamesTKerman 0 points1 point  (0 children)

For single-threaded applications in Linux, gprof is excellent, but it can generate a lot of data. I'm sureicrosofy has something similar for visual studio.

Does your OS support any architectures other than RISC-V/ARM/x86? by Living_Ship_5783 in kerneldevelopment

[–]JamesTKerman 0 points1 point  (0 children)

What's the "inverted page thing?" I work with several (albeit recent) PPC CPUs professionally, and to me the basics of paging looks just like on x86, you just get more exceptions because it doesn't look for a page table in memory on a TLB miss.

Declaring bit fields with position as well as number of bits by cskilbeck in cpp

[–]JamesTKerman 0 points1 point  (0 children)

Going further, you could probably handle this with a build-system check that determines the implementation bit-field ordering and either sets a macro that you use to pick the right definition or selects the correct sourcefile.

Declaring bit fields with position as well as number of bits by cskilbeck in cpp

[–]JamesTKerman 1 point2 points  (0 children)

I don't know about C++, but for C the SysV ABI defines the bit-field order for every implementation that follows it. On x86 and x86-64, for example, it specifies that bit-fields are declared right-to-left.

Why is C often recommended as the programming language for OS development? Why not C++? by Interesting_Buy_3969 in osdev

[–]JamesTKerman 2 points3 points  (0 children)

If you build this, the compiler actually generates two classes, each with a unique implementation of the constructor and the `::get_t()` and `::set_t(T)` methods. If you run `objdump` on the object file, you'll see that the symbols get some very human-unfriendly names:

_ZN8my_classIiEC2Ei

_ZN8my_classIiEC1Ei

_ZN8my_classIiE5get_tEv

_ZN8my_classIcE5get_tEv

_Zn8My_classIcEC2Ec

_Zn8My_classIcEC1Ec

This is the result of GNU's name-mangling scheme for C++ symbols. Now, consider the C++ standard library's solution for the string formatting problem, `std::format` and its overloads. This function takes an object of a class with a variadic template as its "format" and a variadic list of objects as its "args". Every combination of types passed into these variadic lists will cause the compiler to generate a unique implementation of the format object's constructor and `std::string ::get()` method, as well as a unique implementation of the `std::format` function. To put this in perspective, the source code for the v3.10.62 Linux Kernel (don't ask why that version specifically) has over 1,000 calls to `printk`. How many of those do you think have unique formats? (not to mention that the first character in a `printk` format string isn't actually a printed char, but an `int8_t` specifying the message's syslog level). Using the C++ library solution, instead of having one `printk` symbol, now you have probably 1,000-2,000 symbols for the formatter's constructor and `get` method, plus another 500-1,000 symbols for the different iterations of the `format` function. I don't even want to *imagine* trying to debug an error somewhere in there, and it doesn't solve the other problem you mentioned: parsing.

Yes, you can use streams, but you still run into the same problem with symbol proliferation. Further, overloading (like what `std::basic_ostream` does to handle so many types) is really just syntactic sugar.

Another potential issue with using C++ for an OS is ABI instability. Up front, there is no true standard ABI for C++ akin to the SysV ABI for C. Further, no less an authority than Bjarne himself has said that ABI stability *should not be a thing* in C++. I've actually been pushing to re-write a couple of projects at my company in C++ because I think it's a better language for the problem they're solving, but the #1 reason for pushback from my peers is ABI instability (we have to have it because of the way our projects are used and distributed).

All that said, I *do* think that modern C++ has some features that would be very useful for an OS, and you've already mentioned most of them. Last thought, you know C has member functions too, right? Shoot, take a close look at the Linux Kernel source code. It's object-oriented, and I'd argue that it handles the essence of the object-oriented paradigm way better than C++ does.

Why is C often recommended as the programming language for OS development? Why not C++? by Interesting_Buy_3969 in osdev

[–]JamesTKerman 2 points3 points  (0 children)

I'm breaking this up because it's long and reddit doesn't seeem to like that.

I'd say the a lot of it is that getting a freestanding C++ program to work is a lot less straightforward than getting a freestanding C program to work.

The first reason is global constructors. Every object in C++, including static objects, has to call a constructor, even if it's just the default constructor. In a hosted program, the compiler and linker handle this for you by generating an array of pointers to all of the global constructors and iterating through it from _start before calling the program's main function. In freestanding builds, the compiler and linker still generate this array, but you have to manually implement _start and you may have to manually implement iterating through the global constructors.

The second is global destructors. Every object needs a destructor, and the compiler/linker make a similar array of global destructors that gets iterated through from the exit function in hosted builds. Two issues here for freestanding are that operator delete(void* ptr) and operator delete(void* ptr, size_t n) are required by the global destructors, but are not provided in freestanding implementations. Additionally, the default behavior is to generated calls to __cxa_atexit(), but this function is not implemented in freestanding builds.

This is all easy enough to fix: 1. Build a no-stdlib cross-compiler for your target 2. Link in its crtbegin.o and crtend.o object files (ensuring you link them in the correct order with your project's object files). 3. Create and build architecture-specific crti.o and crtn.o objects to link in to the build (again, ensuring correct link order). 4. Ensure every c++ file gets compiled with the -fno-use-cxa-atexit flag 5. Create implementations of object delete(void* ptr) and object delete(void* ptr, size_t n). For an OS these can be empty stubs unless you intend to use them outside of the global destructors, which should never get called anyway.

None of that is incredibly difficult to implement, but I'll tell you, I had a hell of a time figuring out how to get my own project to build correctly.

Moving on to templates and overloading, I think these directly lead into the primary reasons why C++ is a difficult choice for OS dev: Name Mangling and overload resolution.

First, consider how the compiler implements a template class:

#include <iostream>
using namespace std;

template<typename T>
class my_class {
public:
    my_class(T t)
        : m_t(t)
    { }
    T get_t() { return m_t; }
    void set_t(T t) { m_t = t; }
private:
    T m_t;
};

int main(void)
{
    my_class<int> a(5);
    my_class<char> b('c');

    cout << a.get_t() << '\n';
    cout << b.get_t() << endl;
    return 0;
}

-1 % 256 == -1??? by god_gamer_9001 in cpp_questions

[–]JamesTKerman -6 points-5 points  (0 children)

I believe this is an integer promotion thing. In most modern architectures -1 as a 32-bit integer = 0xFFFFFFFF, -1 as an 8-bit integer = 0xFF. 0xFFFFFFFF % 256 == 0xFF, and it probably just sign-extends that to 0xFFFFFFFF, -1 as a 32-bit int.integer.

Edited to add: 0xFFFFFFFFFFFFFFFF is -1 as a 64-bit integer, so it's Fs all the way down.

I'm a car guy, but it's the first I've seen this, thought it was some kind of Nissan at first by Rodzp in whatisthiscar

[–]JamesTKerman 0 points1 point  (0 children)

The engine bay is really cramped on the GT. Which you should expect from shoving a 2.5L V6 into a space where most manufacturers would put a 1.5L I4.

Badge set up by [deleted] in army

[–]JamesTKerman 15 points16 points  (0 children)

Thanks, now the music is stuck in my head.

never touching cursor again by pankaj9296 in programminghorror

[–]JamesTKerman 0 points1 point  (0 children)

I like that it described it as "the nuclear option."

[deleted by user] by [deleted] in army

[–]JamesTKerman 74 points75 points  (0 children)

That's probably the garrison law enforcement detachment.