I'm pretty new to Cobol and I'm having difficulty figuring out how to use the structs. What would the C structs below look like when they are converted into Cobol?
These are the structs I have:
struct dataT
{
int m;
};
struct stack
{
int top;
struct dataT items[STACKSIZE];
} st;
How would this statement be represented in Cobol?
st.items[st.top].m
This is very much a stab in the dark since I've never written a line of COBOL before today1. However, after a little googling2 and playing around in ideone, I think I've at least captured the flavor of what the code would look like, if not the actual solution:
IDENTIFICATION DIVISION.
PROGRAM-ID. IDEONE.
ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-STACK.
05 WS-TOP PIC 9 VALUE 0.
05 WS-ITEMS OCCURS 10 TIMES INDEXED BY I.
10 WS-M PIC 9 VALUE 0.
PROCEDURE DIVISION.
ADD 1 TO WS-TOP.
MOVE 9 TO WS-M(WS-TOP).
ADD 1 TO WS-TOP.
MOVE 8 to WS-M(WS-TOP).
DISPLAY "WS-STACK :" WS-STACK.
DISPLAY "WS-TOP :" WS-TOP.
DISPLAY "WS-ITEMS[WS-STACK.WS-TOP].M :" WS-M(WS-TOP).
SUBTRACT 1 FROM WS-TOP.
DISPLAY "WS-TOP :" WS-TOP.
DISPLAY "WS-ITEMS[WS-STACK.WS-TOP].M :" WS-M(WS-TOP).
STOP RUN.
Yes, size is hardcoded to 10 (don't know how to do symbolic constants in COBOL), and WS-TOP and WS-M can only store values from 0 to 9.
Needless to say, data types in COBOL and C are very different. I haven't actually created a new stack type; I've declared a single data items with a couple of sub-items, one of which is a table that can store 10 instances of something called WS-M. This is effectively the same as writing
int main( void )
{
int top = 10;
int m[10];
m[--top] = 9;
m[--top] = 8;
printf("top = %d\n", top );
printf("m[%d] = %d", top, m[top] );
top++;
printf("top = %d\n", top );
printf("m[%d] = %d", top, m[top] );
return 0;
}
in C, with the main difference being that I wrote the C code such that the stack grows "downwards" (which is more natural). As far as I could tell in the ten minutes I spent going through that COBOL tutorial, COBOL does not really have an equivalent to a struct type; even though data items can be grouped in a hierarchical manner, you're not creating a new struct or record type as such. If I wanted multiple stacks, I'd have to declare multiple, separate backing stores and index variables.
I think.
I'll have to do a little more reading.
1. At this point in the day I would rather work on just about anything other than the problem in front of me right now, and I've always been curious about how the other half lived. Also, I'm working on an online banking platform and I know half our backends are written in COBOL, so it wouldn't hurt to take sime time to learn it.
2. I cannot vouch for the quality of this tutorial; it's the first one I found that seemed reasonably complete and easy to read.
You would do that like so:
*> Not a symbolic constant, but if it is never referenced as a
*> target of a move/compute, the compiler should recognize that.
*> and tune for that.
01 Stack-Size Pic S9(8) comp-4 Value <<some-number>>.
*> The "comp-4" data type is a twos complement integer, S9(8) makes
*> it a 32-bit word. Depending upon your compiler, you will sometimes
*> see "binary" or "comp-5"
01 My-Stack.
02 Stack-Top Pic S9(8) comp-4 Value 0.
02 Stack-Items occurs 0 to <<some-maximum-size>>
depending on Stack-Size.
*>-------*
*> This is your data structure, if you made it a copybook, you would have
*> the similar effect of having the struct def from the C code. You can
*> use the copy/replacing features if you need to make multipule data
*> items with different names.
*>
03 Stack-M Pic S9(8) comp-5.
*>-------*
To access the current value on top of the stack:
Move Stack-M (Stack-Top) to where-ever
Some helpful paragraphs:
Pop-Stack.
Move 0 to Stack-M (Stack-Top)
Subtract 1 from Stack-Top
Exit.
Push-Stack.
Add 1 to Stack-Top
Move <<whatever value>> to Stack-M (Stack-Top)
Exit.
Related
Was asked to wrap a blocking call to non-blocking during an interview today.
So we (the interviewer and me) decided to achieve that by adding a background thread inside the nonblocking API.
Here is the code I wrote:
30 #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
31
32 struct SensorReading records[60*10] = {{0}};
33 size_t head = 0;
34
35
36 void * worker_thread(void *arg) {
37 while (1) {
38 size_t idx = (head + 1) % ARRAY_SIZE(records);
39 records[idx] = read_next_sample();
40 head = idx;
41 }
42 }
43
44 float get_most_recent_lux() {
45 static pthread_t worker = -1;
46 if (-1 == worker) {
47 struct SensorReading r = read_next_sample(); // This is the blocking call
48 records[0] = r;
49 if (-1 == pthread_create(&worker, NULL, worker_thread, NULL)) {
50 // error handling
51 }
52 return r.lux;
53 }
54 return records[head].lux;
55 }
Let me explain a little bit here:
read_next_sample() is the blocking call provided;
line 44 get_most_recent_lux() is the wrapped non-blocking API I need to provide.
Internally, it starts a thread which executes the worker_thread() function defined in line 36.
worker_thread() keeps calling the blocking call and writes data to a ringbuf.
So the reader can read most recent record data from the ringbuf.
Also please be noted:
This programming language used here is C, not C++.
This is a single reader single writer case.
This is different than producer-consumer problem, since the wrapped API get_most_recent_lux() should always return most recent data.
Since this is a single reader single writer case, I believe:
No lock required here.
No atomic values required here.
(so the head in line 33 is not declared as atomic values,
and I use a normal evaluation operation (head = idx) in line 40).
Question: Is my above statement correct?
The interviewer keeps telling me that my statement is not correct for all CPU arch, so he believes mutex or atomic variable is required here.
But I don't think so.
I believe, indeed, the single line evaluation C code (head = idx) can be translated to multiple assembly instructions, but only the last assembly instruction is for storing the updated value to the memory. So,
before the last assembly instruction executed, the updated value has not been updated to the memory yet, so the reader will always read the old head value.
after the last assembly instruction executed, the reader will always read the updated head value.
in both case, it is safe, no corruption will happen.
There is no other possibilities. Within a specified time period where only 1 write can happen (let's say change from 1 to 2), the reader can only read either 1 or 2, the reader will never read any value other than 1 or 2, like 0, 3, or 1.5.
Agree?
I really can not believe there is any CPU arch that the code won't work.
If there is, please educate me.
Thanks very much.
You don't need any atomic RMWs or seq_cst, but you do need _Atomic to do release-store and acquire-load to/from head.
That only happens for free on x86 (and SPARC), not other ISAs, and is still unsafe vs. compile-time reordering even when targeting x86. head = idx; could become visible to the other core before the updates to records[idx], letting it read the stale values.
(Well, the records[head].lux load part will actually work on most ISAs like mo_consume, since ISAs other than DEC Alpha guarantee dependency ordering for loads.)
I think there are some other similar Q&As on SO about trying to use non-atomic variables for inter-thread communication. There's little point, just use atomic_store_explicit with memory_order_release - it will compile the same on x86 as a non-atomic store, but with compile time ordering guarantees. So you're not gaining efficiency by avoiding stdatomic.h, if you only use acquire and release. (Except for loads - if you want actual dependency-ordering without a barrier on weakly-ordered ISAs, you have to use relaxed under controlled conditions on weakly-ordered ISAs, because consume is currently semi-deprecated and promotes to acquire in current compilers.) See When to use volatile with multi threading? for more about why hand-rolled atomics work and why they have no advantage.
Also, note that you have no protection against the queue becoming full and overwriting values that haven't been read yet. SPSC queues like this typically have the consumer side update a read index that the writer can check.
I tried compiling the following c-code using MSVC into assembly both with (CL TestFile.c /Fa /Ot) and without optimizations (CL TestFile.c /Fa) and the result is they produce the same stack-depth.
Why does the compiler use 8 bytes for each of the 3 varibles x, y, and z when it knows it will use a maximum of 16 bytes? Instead of y$1 = 4 and z$2 = 8 could it not use y$1 = 4 and z$2 = 4 so y and z use the same memory on the stack without any problems?
int main() {
int x = 123;
if (x == 123) {
int y = 321;
}
else {
int z = 234;
}
}
; Parts of the assembly code
x$ = 0
y$1 = 4
z$2 = 8
main PROC
$LN5:
sub rsp, 24
; And so on...
Nested scopes do not affect stack depth. Per the C standard, nested scopes affect visibility of identifiers and do not impose any requirements on how a C implementation uses the stack, if it has one. A C compiler is permitted by the C standard generate any code that gets the same observable behavior.
For the program shown in the question, the only observable behavior is to exit with a success status, so a good compiler should, when optimizing, generate a minimal program. For example, GCC 10.2 for x86-64 generates just an xor and a ret:
main:
xor eax, eax
ret
So does Clang 11.0.1. If MSVC does not, that is a deficiency in it. (However, it may be that the switches /Os and /Ot do not request optimization or do not request much optimization; they may just express a preference for speed or time when used in conjunction with other optimization switches.)
Further, a good compiler should perform lifetime analysis of the use of objects, constructing a graph representing where nodes are places in code and are labeled with creations or uses of values and directed edges are potential program control flows (or some equivalent representation of the source code). Then assembler (or intermediate code) should be generated to implement the semantics required by the graph. If two sets of source code have equivalent graphs, the compiler should generate equivalent assembly (or intermediate code) for them (up to some reasonable ability to process complicated graphs) regardless of whether definitions in nested scopes were used or not.
I have found no way of inserting a function call depending on previously included variables:
I would like the user call this function
char *call_the_microprocessor_function_with_parameters(char *port, char *pin);
// internally it will concatenate "DDR"+"port"+"pin"
char *result = call_the_microprocessor_function_with_parameters("B", "5");
// will result in "DDRB5"
but how can I then add the call DDRB5 to the code?
// so it results in
DDRB5 = HIGH;
to elaborate: imagine I need to set pin 5 of port B high to toggle an LED, I would call:
#include <microprocessor_library.h>
char *result = call_the_microprocessor_function_with_parameters("B", "5");
TheMagicFunctionJustWritesTheNameOfFunction(result) = HIGH;
//equivalent to
DDRBB5 = HIGH
// this would be the call to the actual microprocessor library
I tried with #define, but that resulted in a lot of issues
and if I want to use function pointers and strcmp's, with four ports each having 8 pins, it would result in 32 switch statements
is this an example of reflection (which is not possible in pure c)?
C is compiled and cant modify its own code.
You have three options:
use OO language. Create objects and you will have this level of abstraction. How you will tag the objects it language and programmer dependent.
Write the C program which will emit the new C code, build the executable. Run the new program. You can repeat those steps ad infinitum.
Choose the interpreted language which can modify itself -
I'm trying to hot patch an exe in memory, the source is available but I'm doing this for learning purposes. (so please no comments suggesting i modify the original source or use detours or any other libs)
Below are the functions I am having problems with.
vm_t* VM_Create( const char *module, intptr_t (*systemCalls)(intptr_t *), vmInterpret_t interpret )
{
MessageBox(NULL, L"Oh snap! We hooked VM_Create!", L"Success!", MB_OK);
return NULL;
}
void Hook_VM_Create(void)
{
DWORD dwBackup;
VirtualProtect((void*)0x00477C3E, 7, PAGE_EXECUTE_READWRITE, &dwBackup);
//Patch the original VM_Create to jump to our detoured one.
BYTE *jmp = (BYTE*)malloc(5);
uint32_t offset = 0x00477C3E - (uint32_t)&VM_Create; //find the offset of the original function from our own
memset((void*)jmp, 0xE9, 1);
memcpy((void*)(jmp+1), &offset, sizeof(offset));
memcpy((void*)0x00477C3E, jmp, 5);
free(jmp);
}
I have a function VM_Create that I want to be called instead of the original function. I have not yet written a trampoline so it crashes (as expected). However the message box does not popup that I have detoured the original VM create to my own. I believe it is the way I'm overwriting the original instructions.
I can see a few issues.
I assume that 0x00477C3E is the address of the original VM_Create function. You really should not hard code this. Use &VM_Create instead. Of course this will mean that you need to use a different name for your replacement function.
The offset is calculated incorrectly. You have the sign wrong. What's more the offset is applied to the instruction pointer at the end of the instruction and not the beginning. So you need to shift it by 5 (the size of the instruction). The offset should be a signed integer also.
Ideally, if you take into account my first point the code would look like this:
int32_t offset = (int32_t)&New_VM_Create - ((int32_t)&VM_Create+5);
Thanks to Hans Passant for fixing my own silly sign error in the original version!
If you are working on a 64 bit machine you need to do your arithmetic in 64 bits and, once you have calculated the offset, truncate it to a 32 bit offset.
Another nuance is that you should reset the memory to being read-only after having written the new JMP instruction, and call FlushInstructionCache.
I'm writing some code which stores some data structures in a special named binary section. These are all instances of the same struct which are scattered across many C files and are not within scope of each other. By placing them all in the named section I can iterate over all of them.
In GCC, I use _attribute_((section(...)) plus some specially named extern pointers which are magically filled in by the linker. Here's a trivial example:
#include <stdio.h>
extern int __start___mysection[];
extern int __stop___mysection[];
static int x __attribute__((section("__mysection"))) = 4;
static int y __attribute__((section("__mysection"))) = 10;
static int z __attribute__((section("__mysection"))) = 22;
#define SECTION_SIZE(sect) \
((size_t)((__stop_##sect - __start_##sect)))
int main(void)
{
size_t sz = SECTION_SIZE(__mysection);
int i;
printf("Section size is %u\n", sz);
for (i=0; i < sz; i++) {
printf("%d\n", __start___mysection[i]);
}
return 0;
}
I'm trying to figure out how to do this in MSVC but I'm drawing a blank. I see from the compiler documentation that I can declare the section using __pragma(section(...)) and declare data to be in that section with __declspec(allocate(...)) but I can't see how I can get a pointer to the start and end of the section at runtime.
I've seen some examples on the web related to doing _attribute_((constructor)) in MSVC, but it seems like hacking specific to CRT and not a general way to get a pointer to the beginning/end of a section. Anyone have any ideas?
There is also a way to do this with out using an assembly file.
#pragma section(".init$a")
#pragma section(".init$u")
#pragma section(".init$z")
__declspec(allocate(".init$a")) int InitSectionStart = 0;
__declspec(allocate(".init$z")) int InitSectionEnd = 0;
__declspec(allocate(".init$u")) int token1 = 0xdeadbeef;
__declspec(allocate(".init$u")) int token2 = 0xdeadc0de;
The first 3 line defines the segments. These define the sections and take the place of the assembly file. Unlike the data_seg pragma, the section pragma only create the section.
The __declspec(allocate()) lines tell the compiler to put the item in that segment.
From the microsoft page:
The order here is important. Section names must be 8 characters or less. The sections with the same name before the $ are merged into one section. The order that they are merged is determined by sorting the characters after the $.
Another important point to remember are sections are 0 padded to 256 bytes. The START and END pointers will NOT be directly before and after as you would expect.
If you setup your table to be pointers to functions or other none NULL values, it should be easy to skip NULL entries before and after the table, due to the section padding
See this msdn page for more details
First of all, you'll need to create an ASM-file containing all the sections you are interested (for ex., section.asm):
.686
.model flat
PUBLIC C __InitSectionStart
PUBLIC C __InitSectionEnd
INIT$A SEGMENT DWORD PUBLIC FLAT alias(".init$a")
__InitSectionStart EQU $
INIT$A ENDS
INIT$Z SEGMENT DWORD PUBLIC FLAT alias(".init$z")
__InitSectionEnd EQU $
INIT$Z ENDS
END
Next, in your code you can use the following:
#pragma data_seg(".init$u")
int token1 = 0xdeadbeef;
int token2 = 0xdeadc0de;
#pragma data_seg()
This gives such a MAP-file:
Start Length Name Class
0003:00000000 00000000H .init$a DATA
0003:00000000 00000008H .init$u DATA
0003:00000008 00000000H .init$z DATA
Address Publics by Value Rva+Base Lib:Object
0003:00000000 ?token1##3HA 10005000 dllmain.obj
0003:00000000 ___InitSectionStart 10005000 section.obj
0003:00000004 ?token2##3HA 10005004 dllmain.obj
0003:00000008 ___InitSectionEnd 10005008 section.obj
So, as you can see it, the section with the name .init$u is placed between .init$a and .init$z and this gives you ability to get the pointer to the begin of the data via __InitSectionStart symbol and to the end of data via __InitSectionEnd symbol.
I was experimenting here a bit and tried to implement the version without an assembly file, however was struggling with the random number of padding bytes between the sections, which makes it almost impossible to find the start of the .init$u section part if content isn't just pointers or other simple items that could be checked for NULL or some other known pattern.
Whether padding is inserted seems to correlate with the use of debug option Zi. When given, padding is inserted, without, all sections appear exactly in the way one would like to have them.
ML64 allows to cut a lot of the assembly noise :
public foo_start
public foo_stop
.code foo$a
foo_start:
.code foo$z
foo_stop:
end